Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
45321a7
avoid that host initialisation scripts are run
truib Mar 14, 2025
03a57d4
Merge pull request #307 from trz42/contain_the_container
bedroge Mar 14, 2025
c6048c7
use bot's app_name as namespace when signing files
truib Mar 14, 2025
0aaf7b8
adjust and extend CI for sign/verify script
truib Mar 14, 2025
0f67582
Use named arguments and parsing in ssh signing script
ocaisa Mar 17, 2025
8da77b0
Wrong path to script in final check
ocaisa Mar 17, 2025
1813229
Also run the tests when the testing changes
ocaisa Mar 17, 2025
eefaec1
Fix test issue
ocaisa Mar 17, 2025
7a2b0e2
Be more careful with variables between steps
ocaisa Mar 17, 2025
c16b5ff
Merge pull request #5 from ocaisa/tweak_namespace_script
trz42 Mar 17, 2025
5a97702
Merge pull request #308 from trz42/use_bot_name_as_namespace
ocaisa Mar 17, 2025
772a626
delete pre-existing signature files + small fixes
truib Mar 18, 2025
5ff1b77
Merge pull request #309 from trz42/remove_pre_existing_sig_files
ocaisa Mar 19, 2025
bb146dd
determine test coverage and upload report
truib Apr 1, 2025
8f43b22
add missing dash
truib Apr 1, 2025
57d38f3
just produce plain ASCII report and don't upload it
truib Apr 1, 2025
f40eefc
fix newly reported global var issue
truib Apr 1, 2025
47f8206
add extra step for coverage
truib Apr 1, 2025
dd6ffed
run steps with different options
truib Apr 1, 2025
581cf99
use newer version of pytest-cov
truib Apr 1, 2025
5a1f531
attempt to only show the coverage summary
truib Apr 1, 2025
3dad259
debug step error
truib Apr 1, 2025
ed70318
remove requirement for recent version of pytest-cov
truib Apr 1, 2025
f29ec64
cov-report=term does not support location
truib Apr 1, 2025
d4b4811
Merge pull request #311 from trz42/check_coverage_tests
boegel Apr 3, 2025
426b4a1
make bot chattiness configurable
smoors May 3, 2025
bfc6f27
add missing import
smoors May 4, 2025
4a7c833
add incognito chatlevel
smoors May 7, 2025
da8480d
use Ubuntu 24.04 in CI
boegel May 7, 2025
57c50c4
Merge pull request #316 from boegel/ci
trz42 May 7, 2025
445419a
Merge branch 'develop' into chatlevel
smoors May 7, 2025
5b2647e
fix tests
smoors May 8, 2025
7604a70
remove unused imports
smoors May 8, 2025
f85be5c
Merge pull request #315 from smoors/chatlevel
trz42 May 22, 2025
ac5fd3b
release notes for v0.8.0
truib May 23, 2025
450973d
Merge pull request #318 from trz42/release_notes_v0.8.0
bedroge May 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ on: [push, pull_request]
permissions: read-all
jobs:
test:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
python: [3.6, 3.7, 3.8, 3.9, '3.10', '3.11']
# for now, only test with Python 3.9+ (since we're testing in Ubuntu 24.04)
#python: [3.6, 3.7, 3.8, 3.9, '3.10', '3.11']
python: ['3.9', '3.10', '3.11']
fail-fast: false
steps:
- name: checkout
Expand All @@ -38,9 +40,14 @@ jobs:
python -m pip install pytest
python -m pip install --upgrade flake8

- name: Run test suite
- name: Run test suite (without coverage)
run: |
./test.sh
./test.sh --verbose

- name: Run test suite (with coverage)
run: |
python -m pip install pytest-cov
./test.sh -q --cov=$PWD

- name: Run flake8 to verify PEP8-compliance of Python code
run: |
Expand Down
69 changes: 52 additions & 17 deletions .github/workflows/tests_scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,71 @@ on:
push:
paths:
- scripts/sign_verify_file_ssh.sh
- .github/workflows/tests_scripts.yml
pull_request:
paths:
- scripts/sign_verify_file_ssh.sh
- .github/workflows/tests_scripts.yml
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: test sign_verify_file_ssh.sh script
run: |
# Create a PEM format ssh identity
- name: Prepare SSH key pair, file and signature
run: |
ssh-keygen -t rsa -b 4096 -m PEM -f id_rsa.pem -N ""
# Create a file to sign
echo "Very important stuff" > out.txt
export FILE_TO_SIGN="out.txt"
# Sign the file
./scripts/sign_verify_file_ssh.sh sign id_rsa.pem "$FILE_TO_SIGN"
# Create an allowed_signers file based on the public key
echo -n "allowed_identity " > allowed_signers
./scripts/sign_verify_file_ssh.sh --sign --private-key id_rsa.pem --file "$FILE_TO_SIGN" --namespace ci

- name: Create allowed signers file and verify
run: |
valid_before=$(date --date='today+3days' +%Y%m%d)
echo -n 'allowed_identity namespaces="ci",valid-before="'$valid_before'" ' > allowed_signers
cat id_rsa.pem.pub >> allowed_signers
# Verify the signature
./scripts/sign_verify_file_ssh.sh verify allowed_signers "$FILE_TO_SIGN"
# Make a new signature that does not appear in the allowed signers file
./scripts/sign_verify_file_ssh.sh --verify --allowed-signers-file allowed_signers --file out.txt

- name: Replace allowed signers with disallowed identity
run: |
valid_before=$(date --date='today+3days' +%Y%m%d)
ssh-keygen -t rsa -b 4096 -m PEM -f id_rsa.alt.pem -N ""
# Replace the allowed signers file
echo -n "disallowed_identity " > allowed_signers
echo -n 'disallowed_identity namespaces="ci",valid-before="'$valid_before'" ' > allowed_signers
cat id_rsa.alt.pem.pub >> allowed_signers
# Make sure signature checking fails in this case
./scripts/sign_verify_file_ssh.sh verify allowed_signers "$FILE_TO_SIGN" && exit 1 || echo "Expected failure for unknown identity"

- name: Ensure verification fails for unknown identity
run: |
./scripts/sign_verify_file_ssh.sh --verify --allowed-signers-file allowed_signers --file out.txt && exit 1 || echo "Expected failure for unknown identity"

- name: Replace allowed signers with wrong namespace
run: |
valid_before=$(date --date='today+3days' +%Y%m%d)
echo -n 'wrong_namespace_identity namespaces="CI",valid-before="'$valid_before'" ' > allowed_signers
cat id_rsa.pem.pub >> allowed_signers

- name: Ensure verification fails for wrong namespace
run: |
./scripts/sign_verify_file_ssh.sh --verify --allowed-signers-file allowed_signers --file out.txt && exit 2 || echo "Expected failure for wrong namespace"

- name: Replace allowed signers with expired key
run: |
valid_expired=$(date --date='today-3days' +%Y%m%d)
echo -n 'expired_key_identity namespaces="ci",valid-before="'$valid_expired'" ' > allowed_signers
cat id_rsa.pem.pub >> allowed_signers

- name: Ensure verification fails for expired key
run: |
./scripts/sign_verify_file_ssh.sh --verify --allowed-signers-file allowed_signers --file out.txt && exit 3 || echo "Expected failure for expired key"

- name: Ensure verification when looping through allowed signers file
run: |
# Add the approved identity to the end
valid_before=$(date --date='today+3days' +%Y%m%d)
echo -n 'listed_identity namespaces="ci",valid-before="'$valid_before'" ' >> allowed_signers
cat id_rsa.pem.pub >> allowed_signers
./scripts/sign_verify_file_ssh.sh --verify --allowed-signers-file allowed_signers --file out.txt
# Make sure we get exactly what we want in terse mode
./scripts/sign_verify_file_ssh.sh --verify --allowed-signers-file allowed_signers --file out.txt --terse | grep -q '{\"identity\": \"listed_identity\", \"namespace\": \"ci\"}'
19 changes: 19 additions & 0 deletions RELEASE_NOTES
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
This file contains a description of the major changes to the EESSI
build-and-deploy bot. For more detailed information, please see the git log.

v0.8.0 (23 May 2025)
--------------------------

This is a minor release of the EESSI build-and-deploy bot.

Bug fixes:
* use Ubuntu 24.04 in CI (#316)
* delete pre-existing signature files (#309)

Improvements:
* adding argument `--contain` when launching the build container (#307)
* use the bot instance's name as `namespaces` value in a signature (#308)
* determine test coverage (#311)
* support different levels for when a bot instance creates comments on GitHub (#315)

Changes to 'app.cfg' settings (see README.md and app.cfg.example for details):
* NEW (optional) 'chatlevel' in section '[bot_control]'


v0.7.0 (13 March 2025)
--------------------------

Expand Down
2 changes: 2 additions & 0 deletions app.cfg.example
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ command_response_fmt =
{comment_result}
</details>

# chattiness level of the bot in terms of writing comments into PRs (minimal, basic, or chatty)
chatlevel = basic

[buildenv]
# name of the job script used for building an EESSI stack
Expand Down
3 changes: 1 addition & 2 deletions connections/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def get_instance():
Returns:
Instance of Github
"""
global _gh, _token
global _gh

# Check if PyGithub version is < 1.56
if hasattr(github, 'GithubRetry'):
Expand Down Expand Up @@ -129,5 +129,4 @@ def token():
Returns:
Token
"""
global _token
return _token
60 changes: 31 additions & 29 deletions eessi_bot_event_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@
from tools.commands import EESSIBotCommand, EESSIBotCommandError, \
contains_any_bot_command, get_bot_command
from tools.permissions import check_command_permission
from tools.pr_comments import create_comment
from tools.pr_comments import ChatLevels, create_comment


REQUIRED_CONFIG = {
config.SECTION_ARCHITECTURETARGETS: [
config.ARCHITECTURETARGETS_SETTING_ARCH_TARGET_MAP], # required
config.SECTION_BOT_CONTROL: [
# config.BOT_CONTROL_SETTING_CHATLEVEL, # optional
config.BOT_CONTROL_SETTING_COMMAND_PERMISSION, # required
config.BOT_CONTROL_SETTING_COMMAND_RESPONSE_FMT], # required
config.SECTION_BUILDENV: [
Expand Down Expand Up @@ -193,6 +194,8 @@ def handle_issue_comment_event(self, event_info, log_file=None):
return
# at this point we know that we are handling a new comment

issue_comment = None

# check if comment does not contain a bot command
if not contains_any_bot_command(comment_received):
self.log("comment does not contain a bot comment; not processing it further")
Expand Down Expand Up @@ -229,7 +232,7 @@ def handle_issue_comment_event(self, event_info, log_file=None):
comment_response=comment_response,
comment_result=''
)
issue_comment = create_comment(repo_name, pr_number, comment_body)
issue_comment = create_comment(repo_name, pr_number, comment_body, ChatLevels.CHATTY)
else:
self.log(f"account `{sender}` seems to be a bot instance itself, hence not creating a new PR comment")
return
Expand Down Expand Up @@ -263,6 +266,11 @@ def handle_issue_comment_event(self, event_info, log_file=None):
# including a bot command; the logging should only be done when log
# level is set to debug

if 'help' in (x.command for x in commands):
req_chatlevel = ChatLevels.MINIMAL
else:
req_chatlevel = ChatLevels.CHATTY

if comment_response == '':
# no update to be added, just log and return
self.log("comment response is empty")
Expand All @@ -281,7 +289,7 @@ def handle_issue_comment_event(self, event_info, log_file=None):
comment_response=comment_response,
comment_result=''
)
issue_comment = create_comment(repo_name, pr_number, comment_body)
issue_comment = create_comment(repo_name, pr_number, comment_body, req_chatlevel)
else:
self.log(f"update '{comment_response}' is considered to contain bot command ... not creating PR comment")
# TODO we may want to report this back to the PR on GitHub, e.g.,
Expand All @@ -306,24 +314,26 @@ def handle_issue_comment_event(self, event_info, log_file=None):
continue
except Exception as err:
log(f"Unexpected err={err}, type(err)={type(err)}")
if comment_result:
if comment_result and issue_comment:
comment_body = command_response_fmt.format(
app_name=app_name,
comment_response=comment_response,
comment_result=comment_result
)
issue_comment.edit(comment_body)
raise
# only update PR comment once, that is, a single call to
# issue_comment.edit is made in the entire function
comment_body = command_response_fmt.format(
app_name=app_name,
comment_response=comment_response,
comment_result=comment_result
)
issue_comment.edit(comment_body)

self.log(f"issue_comment event (url {issue_url}) handled!")
if issue_comment:
# only update PR comment once, that is, a single call to
# issue_comment.edit is made in the entire function
comment_body = command_response_fmt.format(
app_name=app_name,
comment_response=comment_response,
comment_result=comment_result
)
issue_comment.edit(comment_body)

self.log(f"issue_comment event (url {issue_url}) handled!")

def handle_installation_event(self, event_info, log_file=None):
"""
Expand Down Expand Up @@ -373,14 +383,14 @@ def handle_pull_request_labeled_event(self, event_info, pr):
comment_response=msg,
comment_result=''
)
create_comment(repo_name, pr_number, comment_body)
create_comment(repo_name, pr_number, comment_body, ChatLevels.BASIC)
elif label == "bot:deploy":
# run function to deploy built artefacts
deploy_built_artefacts(pr, event_info)
else:
self.log("handle_pull_request_labeled_event: no handler for label '%s'", label)

def handle_pull_request_opened_event(self, event_info, pr):
def handle_pull_request_opened_event(self, event_info, pr, req_chatlevel=ChatLevels.CHATTY):
"""
Handle events of type pull_request with the action opened. Main action
is to report for which architectures and repositories a bot instance is
Expand Down Expand Up @@ -420,10 +430,7 @@ def handle_pull_request_opened_event(self, event_info, pr):

# create comment to pull request
repo_name = pr.base.repo.full_name
gh = github.get_instance()
repo = gh.get_repo(repo_name)
pull_request = repo.get_pull(pr.number)
issue_comment = pull_request.create_issue_comment(comment)
issue_comment = create_comment(repo_name, pr.number, comment, req_chatlevel)
return issue_comment

def handle_pull_request_event(self, event_info, log_file=None):
Expand Down Expand Up @@ -554,8 +561,9 @@ def handle_bot_command_show_config(self, event_info, bot_command):
repo_name = event_info['raw_request_body']['repository']['full_name']
pr_number = event_info['raw_request_body']['issue']['number']
pr = gh.get_repo(repo_name).get_pull(pr_number)
issue_comment = self.handle_pull_request_opened_event(event_info, pr)
return f"\n - added comment {issue_comment.html_url} to show configuration"
issue_comment = self.handle_pull_request_opened_event(event_info, pr, req_chatlevel=ChatLevels.MINIMAL)
if issue_comment:
return f"\n - added comment {issue_comment.html_url} to show configuration"

def handle_bot_command_status(self, event_info, bot_command):
"""
Expand All @@ -571,7 +579,6 @@ def handle_bot_command_status(self, event_info, bot_command):
PyGithub, not the github from the internal connections module)
"""
self.log("processing bot command 'status'")
gh = github.get_instance()
repo_name = event_info['raw_request_body']['repository']['full_name']
pr_number = event_info['raw_request_body']['issue']['number']
status_table = request_bot_build_issue_comments(repo_name, pr_number)
Expand All @@ -588,9 +595,7 @@ def handle_bot_command_status(self, event_info, bot_command):
comment_status += f"{status_table['url'][x]}|"

self.log(f"Overview of finished builds: comment '{comment_status}'")
repo = gh.get_repo(repo_name)
pull_request = repo.get_pull(pr_number)
issue_comment = pull_request.create_issue_comment(comment_status)
issue_comment = create_comment(repo_name, pr_number, comment_status, ChatLevels.MINIMAL)
return issue_comment

def start(self, app, port=3000):
Expand Down Expand Up @@ -669,12 +674,9 @@ def handle_pull_request_closed_event(self, event_info, pr):
# 4) report move to pull request

repo_name = pr.base.repo.full_name
gh = github.get_instance()
repo = gh.get_repo(repo_name)
pull_request = repo.get_pull(pr.number)
clean_up_comment = self.cfg[config.SECTION_CLEAN_UP][config.CLEAN_UP_SETTING_MOVED_JOB_DIRS_COMMENT]
moved_comment = clean_up_comment.format(job_dirs=job_dirs, trash_bin_dir=trash_bin_dir)
issue_comment = pull_request.create_issue_comment(moved_comment)
issue_comment = create_comment(repo_name, pr.number, moved_comment, ChatLevels.CHATTY)
return issue_comment


Expand Down
Loading
Loading