base-os's nightly asks netOrk's matcher whether a rebuild improves on the pin (image_tools/verify.py). As an action, a workflow needs nothing of this repository but the pinned commit: no install, no checkout. A verdict that could not be reached fails the step, as it does in base-os since the two nights with an empty NETORK_LICENSE_KEY.
This commit is contained in:
1 parent
d139d66c3d
commit
9232b54c6d
3 files changed
+61
-2
No files matched your search
@@ -38,6 +38,16 @@ with its CIS result and SBOM attached (NetOrk/netork#1390).
|
|||||||
image: registry.netork.io/netork/engine:main-abc1234
|
image: registry.netork.io/netork/engine:main-abc1234
|
||||||
arch: amd64
|
arch: amd64
|
||||||
|
|
||||||
|
# a base's nightly, to decide whether its pin moves:
|
||||||
|
- name: Judge it against the pin
|
||||||
|
id: verdict
|
||||||
|
uses: https://git.netork.io/NetOrk/image-tools/actions/verdict@<commit>
|
||||||
|
env:
|
||||||
|
NETORK_LICENSE_KEY: ${{ secrets.NETORK_LICENSE_KEY }}
|
||||||
|
with:
|
||||||
|
current: registry.netork.io/netork/base-os:pinned
|
||||||
|
candidate: registry.netork.io/netork/base-os:13-20261022.3-amd64
|
||||||
|
|
||||||
# push it, then:
|
# push it, then:
|
||||||
- name: Sign it
|
- name: Sign it
|
||||||
uses: https://git.netork.io/NetOrk/image-tools/actions/sign@<commit>
|
uses: https://git.netork.io/NetOrk/image-tools/actions/sign@<commit>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
name: Judge a rebuild against the pin
|
||||||
|
description: >-
|
||||||
|
Whether a candidate improves on the pinned image, by netOrk's matcher in
|
||||||
|
kb-server (image_tools/verify.py). Writes verdict.json and report.md, prints
|
||||||
|
the report, and fails when no verdict could be reached. The caller passes
|
||||||
|
NETORK_LICENSE_KEY, and TRIVY_USERNAME/TRIVY_PASSWORD for the registry, as env.
|
||||||
|
inputs:
|
||||||
|
current:
|
||||||
|
description: The pinned image
|
||||||
|
required: true
|
||||||
|
candidate:
|
||||||
|
description: The rebuild
|
||||||
|
required: true
|
||||||
|
packages:
|
||||||
|
description: The packages the image may hold, for the CIS part of the verdict
|
||||||
|
default: packages.allow
|
||||||
|
outputs:
|
||||||
|
improved:
|
||||||
|
description: '"true" when the candidate improves on the pin'
|
||||||
|
value: ${{ steps.verdict.outputs.improved }}
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- id: verdict
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CURRENT: ${{ inputs.current }}
|
||||||
|
CANDIDATE: ${{ inputs.candidate }}
|
||||||
|
PACKAGES: ${{ inputs.packages }}
|
||||||
|
PYTHONPATH: ${{ github.action_path }}/../..
|
||||||
|
run: |
|
||||||
|
python3 -m image_tools.verify "$CURRENT" "$CANDIDATE" --packages "$PACKAGES" \
|
||||||
|
--json verdict.json --report report.md
|
||||||
|
# Into the log: Gitea shows no step summary.
|
||||||
|
cat report.md
|
||||||
|
cat report.md >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
python3 -c "import json; print('improved=' + str(json.load(open('verdict.json'))['improved']).lower())" >> "$GITHUB_OUTPUT"
|
||||||
|
# A verdict that could not be reached is no "same": the step fails, so it is seen.
|
||||||
|
python3 -c "import json, sys; e = json.load(open('verdict.json'))['error']; sys.exit(f'no verdict: {e}' if e else 0)"
|
||||||
+12
-2
@@ -17,8 +17,8 @@ ROOT = Path(__file__).resolve().parents[1]
|
|||||||
ACTIONS = sorted((ROOT / "actions").glob("*/action.yml"))
|
ACTIONS = sorted((ROOT / "actions").glob("*/action.yml"))
|
||||||
|
|
||||||
|
|
||||||
def test_the_three_actions():
|
def test_the_four_actions():
|
||||||
assert [a.parent.name for a in ACTIONS] == ["judge", "sign", "verify-base"]
|
assert [a.parent.name for a in ACTIONS] == ["judge", "sign", "verdict", "verify-base"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("action", ACTIONS, ids=lambda a: a.parent.name)
|
@pytest.mark.parametrize("action", ACTIONS, ids=lambda a: a.parent.name)
|
||||||
@@ -36,3 +36,13 @@ def test_signing_needs_its_secrets_from_the_caller():
|
|||||||
text = (ROOT / "actions/sign/action.yml").read_text()
|
text = (ROOT / "actions/sign/action.yml").read_text()
|
||||||
|
|
||||||
assert "COSIGN_PRIVATE_KEY_B64" in text and "secrets." not in text
|
assert "COSIGN_PRIVATE_KEY_B64" in text and "secrets." not in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_verdict_that_could_not_be_reached_fails_the_step():
|
||||||
|
"""A silent "same" hid an empty NETORK_LICENSE_KEY for two nights (2026-10-21/22)."""
|
||||||
|
spec = yaml.safe_load((ROOT / "actions/verdict/action.yml").read_text())
|
||||||
|
[step] = spec["runs"]["steps"]
|
||||||
|
|
||||||
|
assert spec["outputs"]["improved"]["value"] == "${{ steps.verdict.outputs.improved }}"
|
||||||
|
assert "['error']" in step["run"] and "sys.exit(" in step["run"]
|
||||||
|
assert "cat report.md" in step["run"].splitlines()
|
||||||
Reference in new issue
Block a user