Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
cache: npm
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
- name: Audit the locked npm dependencies (install-free)
Expand Down Expand Up @@ -186,7 +186,7 @@ jobs:
with:
python-version: "3.14"
- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
- name: Generate the Python engine SBOM (license-complete, hash-locked core runtime)
Expand Down
77 changes: 70 additions & 7 deletions .github/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ rules:
# A CLA assistant REQUIRES pull_request_target to record signatures + comment on fork PRs. This
# workflow never checks out untrusted PR code, pins the third-party action by SHA, and gates on the
# immutable comment body / event name — so the usual pull_request_target risk (running attacker
# code with a write token) does not apply. See the SECURITY note in cla.yml.
# code with a write token) does not apply. The action is pinned at ca4a40a7d100 (v2.6.1); its
# archived-upstream status is adjudicated under archived-uses below.
- cla.yml
# A notice that a SCHEDULED run failed can only be written by something observing that run AFTER
# it finishes — no other trigger sees another workflow's conclusion, so `workflow_run` is not a
Expand All @@ -22,7 +23,9 @@ rules:
# tests/test_nightly_notice.py rather than merely asserted here:
# * NO checkout, and no third-party actions at all — `test_it_pulls_in_no_third_party_actions`
# fails if a `uses:` ever appears. Nothing from the triggering ref is fetched, let alone run.
# That is a STRONGER claim than cla.yml's above, which does check out.
# That is a STRONGER claim than cla.yml's above: cla.yml runs a third-party action with a
# write token — SHA-pinned, so it cannot change under us, but still third-party code —
# whereas this job runs no third-party code at all.
# * It only reacts to `workflow_run.event == 'schedule'`
# (`test_it_only_reacts_to_scheduled_runs`), so a PR — including a fork PR — has no path to
# the job at all.
Expand All @@ -36,16 +39,76 @@ rules:
artipacked:
ignore:
# artipacked flags a checkout that persists the token's git credential — a risk only if that
# credential can leak into an uploaded artifact. The jobs below do not push and never upload the
# repo/.git tree, so the persisted credential is inert noise here.
# credential can leak into an uploaded artifact. The jobs below never upload the repo/.git tree,
# so the persisted credential is inert noise here.
#
# NOT suppressed (fixed at the source instead): release.yml sets persist-credentials: false on both
# checkouts because it DOES upload build artifacts. dependabot-lock-resync.yml persists a
# NOT suppressed (fixed at the source instead): release.yml's checkouts set persist-credentials:
# false, because it DOES upload build artifacts. dependabot-lock-resync.yml persists a
# narrowly-scoped App token ON PURPOSE to push the resynced locks (documented inline) and is listed
# here for that reason.
- benchmark.yml
- ci.yml
- dependabot-lock-resync.yml
- release-sync-check.yml
- security.yml
- vuln-metrics.yml

bot-conditions:
ignore:
# zizmor flags `github.triggering_actor == 'dependabot[bot]'` in the resync job's `if:`, because an
# actor context reflects the LAST actor on the run, not the PR's author. True — and it is why that
# expression is the SECOND half of a conjunction and never the control. The control is the FIRST
# half, `github.event.pull_request.user.login == 'dependabot[bot]'`: the immutable PR author, and
# the exact replacement this audit recommends. A conjunction only NARROWS, so a spoofed actor can
# make this job SKIP, never run. zizmor agrees — it treats `And` as non-dominating and reports this
# at MEDIUM confidence for that reason.
#
# Skipping is safe by design: DEP-1 lock/export sync is independently enforced by security.yml's
# `pip-audit` job, step "Check the lockfile is in sync with pyproject (DEP-1)", which
# `git diff --exit-code`s the re-exports on an unfiltered pull_request trigger and is a REQUIRED
# context. The actor half is an operational self-trigger skip: this job's own App-token push fires
# a `synchronize` whose triggering actor is mefor-lock-resync[bot], a run that sees no Dependabot
# secrets. See the SECURITY MODEL block and the numbered note above that `if:`.
#
# DO NOT TAKE ZIZMOR'S AUTO-FIX. It is classified SAFE, so a bare `zizmor --fix` applies it
# silently: for a `pull_request` trigger it substitutes `github.event.pull_request.user.login`,
# collapsing the conjunction into `A && A` and deleting the self-trigger skip. Nothing in CI would
# catch that — every test and required check stays green while the skip is gone.
#
# The premise this suppression rests on — clause 1 present, conjoined, no `||` — is PINNED by
# tests/test_dep1_lock_resync_lockstep.py rather than merely asserted here. Line-anchored on
# purpose: a file-level entry would also swallow a future actor check added to this file as a SOLE
# gate, which is the shape that IS exploitable. Accepted residual: an in-place rewrite that keeps
# the line count would not re-fire the finding — that is what the test is for. If the line moves,
# RE-ANCHOR it; do not broaden it to the file.
- dependabot-lock-resync.yml:76

archived-uses:
ignore:
# contributor-assistant/github-action is ARCHIVED upstream (GitHub API `archived: true`; the date
# is observed from its last push, 2026-03-23, since `archived_at` is null). v2.6.1 is both the last
# tag and the last release, and the pin ca4a40a7d1004f18d9960b404b97e5f30a505a08 equals that tag
# exactly — so there is no future patch to bump to. Recorded as an ACCEPTED RESIDUAL, not a false
# positive: the finding is true.
#
# What the SHA pin buys, and what it does not. It closes the TAMPER axis completely — a bundled JS
# action's pinned SHA fully determines the bytes that run, and a deleted or re-registered namespace
# makes this step FAIL rather than run a stranger's code. It does NOT close the axis this audit is
# about: a flaw in the code already at that SHA will never be patched.
#
# NOT REPLACED, deliberately. `cla` is a REQUIRED status context (.github/required-contexts.txt)
# and it is this JOB's own conclusion, so a broken step blocks every contribution.
# pull_request_target / issue_comment workflows run only from the DEFAULT branch, so a swap cannot
# be exercised on the PR that makes it — it lands on main untested, with approvals at 0 and
# auto-merge armed. On a step holding a write token that any GitHub user can trigger by comment,
# trading a frozen SHA-pinned bundle for a less-reviewed fork is not self-evidently a security win.
#
# WHAT WILL FORCE THE DECISION, and it is not this lint: action.yml at this SHA declares
# `runs.using: node20`, as does the archived repo's HEAD, so no upstream release can ever
# re-declare node24. GitHub removes Node20 in fall 2026. Re-check before then. Full record and the
# replacement candidate: docs/adr/0034 (amendment, 2026-08-01).
#
# Line-anchored on purpose: a file-level entry would silently swallow a SECOND archived action
# added here later. Accepted cost is drift — an inserted line re-fires the finding with no change
# in risk. Re-anchor; do not broaden. Delete this entry when the action is replaced, or if upstream
# un-archives (the audit re-checks that every run).
- cla.yml:44
24 changes: 12 additions & 12 deletions ci/locks/ci-scanners.lock
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,15 @@ urllib3==2.7.0 \
--hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \
--hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897
# via requests
zizmor==1.5.2 \
--hash=sha256:03b27c46d87e96a0acdf78190fbb674c174f67ded396c74dadd64d7c4ecba680 \
--hash=sha256:0c5f656106c430748858ae459c41c9eed09a1e01e5f42015d80c8fe34740d173 \
--hash=sha256:506b355c693d40df01bdf26fd1dfcb41801af7b8c51767d4159efdc2655965c4 \
--hash=sha256:5e18b06af4208624ef707e7859b07539870ca26b74a89537e1a6bfba2e44fc9a \
--hash=sha256:848f04c0d84b085dfb79c66951404372ebf9b3dd0c73076f1baac83db29e74e4 \
--hash=sha256:86395dd985ed6bf9acffea8a900b30d8d4dd4c9e20421f16f2db7ad92299e24e \
--hash=sha256:8c65b4dbc9690d3f0f5d9756ae0b5ca8d3dfb4f806d82a5195836a3b613ae996 \
--hash=sha256:9d40780b19da7901423de80ccce083a8c0d2114e0cf6432aa20d8e60d15e97f6 \
--hash=sha256:a40feabc2c043aca60f9edbd35a676d97d684af5b06ed61a7752869c79b3be30 \
--hash=sha256:dcef697a88983e7ce6948df1603e2325e2cf5c523828af94615e6c432fa8d98a \
--hash=sha256:df1326fe9f9ddcbe9d862a97571c848276882d0ceeee39e18fcfc9ec5c66cd7b
zizmor==1.28.0 \
--hash=sha256:0949f57a6d20deeb9c509705afce8de233c166475e25be305985a1fe553c6e0d \
--hash=sha256:149dba59a8bd2897960ee54c40ae8b5801a71293bad71c8d2913c74ab66a294c \
--hash=sha256:354e6cb98a15a88593a6f7ac6236b092b83a2aad5c4768ee750f9b3262f668d9 \
--hash=sha256:6897f02b0d02fd709f5ebc13cd37d97ad464219e0ba86a03f6d86f7777b7b102 \
--hash=sha256:6d5a300b80bf4c12e9cbe78ffd3874ec3f94b65bea78c994ec18157e2846ece0 \
--hash=sha256:7b00018cf2cc948c3b3e010c1a1f30fdc001f0d062640469f17e0ef006e74eb7 \
--hash=sha256:833c360ba5a9c74ca45007b8c79939826fca0c5ed65144fa08f63a7009cef096 \
--hash=sha256:9819f91f0ef486e4af98a6aacfed23c6b4067fabcecb88d49231228a3d43f821 \
--hash=sha256:ae2cab67ce713e760e0d1b61ad749d374693ea2b310337aab11cd446748267f3 \
--hash=sha256:c93b30d211b0b0c38905a8803cc2653fff37de03eb77105302a02f709773bd4a \
--hash=sha256:ef69d198dcf6835c9b6eea8673cbc5c36f10b3f1b98b51d28266b7e01c3704d4
4 changes: 2 additions & 2 deletions constraints.lock
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ defusedxml==0.7.1
# pyx12
elementpath==5.1.3
# via xmlschema
fastapi==0.139.2
fastapi==0.140.4
# via messagefoundry
fhir-core==1.1.9
# via fhir-resources
Expand Down Expand Up @@ -152,7 +152,7 @@ pathspec==1.1.1
# via mypy
pluggy==1.6.0
# via pytest
prometheus-client==0.25.0
prometheus-client==0.26.0
# via messagefoundry
protobuf==6.33.6
# via
Expand Down
12 changes: 6 additions & 6 deletions docker/locks/requirements-core.lock
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ defusedxml==0.7.1 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
# via messagefoundry
fastapi==0.139.2 \
--hash=sha256:333145a6891e9b5b3cfceb69baf817e8240cde4d4588ae5a10bf56ffacb6255e \
--hash=sha256:b9ad015a835173d59865e2f5d8296fbc2b317bf56a2ba1a5bfbdd03de2fd4b1c
fastapi==0.140.4 \
--hash=sha256:4a040c5d047486a62c497eb6e926a6d6b281efb7f99b8b50288489ba1fa0a468 \
--hash=sha256:6a1f8ec2f01ae47c96dc991d49660ce4f31f50ed0d7c9df80c5e57037bfe1240
# via messagefoundry
h11==0.16.0 \
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
Expand Down Expand Up @@ -192,9 +192,9 @@ ldap3==2.9.1 \
--hash=sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70 \
--hash=sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f
# via messagefoundry
prometheus-client==0.25.0 \
--hash=sha256:5e373b75c31afb3c86f1a52fa1ad470c9aace18082d39ec0d2f918d11cc9ba28 \
--hash=sha256:d5aec89e349a6ec230805d0df882f3807f74fd6c1a2fa86864e3c2279059fed1
prometheus-client==0.26.0 \
--hash=sha256:04a91bcf94e2cf74a44a1a874d651a2e853ed354b6e822f3b7487751465d5c2b \
--hash=sha256:fa93d06737aa02bacd05794768508bb97d2fbee28cb3bca04eaae92f0ca953d6
# via messagefoundry
psutil==7.2.2 \
--hash=sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372 \
Expand Down
12 changes: 6 additions & 6 deletions docker/locks/requirements-sqlserver.lock
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ defusedxml==0.7.1 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
# via messagefoundry
fastapi==0.139.2 \
--hash=sha256:333145a6891e9b5b3cfceb69baf817e8240cde4d4588ae5a10bf56ffacb6255e \
--hash=sha256:b9ad015a835173d59865e2f5d8296fbc2b317bf56a2ba1a5bfbdd03de2fd4b1c
fastapi==0.140.4 \
--hash=sha256:4a040c5d047486a62c497eb6e926a6d6b281efb7f99b8b50288489ba1fa0a468 \
--hash=sha256:6a1f8ec2f01ae47c96dc991d49660ce4f31f50ed0d7c9df80c5e57037bfe1240
# via messagefoundry
h11==0.16.0 \
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
Expand Down Expand Up @@ -196,9 +196,9 @@ ldap3==2.9.1 \
--hash=sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70 \
--hash=sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f
# via messagefoundry
prometheus-client==0.25.0 \
--hash=sha256:5e373b75c31afb3c86f1a52fa1ad470c9aace18082d39ec0d2f918d11cc9ba28 \
--hash=sha256:d5aec89e349a6ec230805d0df882f3807f74fd6c1a2fa86864e3c2279059fed1
prometheus-client==0.26.0 \
--hash=sha256:04a91bcf94e2cf74a44a1a874d651a2e853ed354b6e822f3b7487751465d5c2b \
--hash=sha256:fa93d06737aa02bacd05794768508bb97d2fbee28cb3bca04eaae92f0ca953d6
# via messagefoundry
psutil==7.2.2 \
--hash=sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372 \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,36 @@ why export sync must be verified with `git diff` and never a raw `diff`. Fixed a
**Still open, not done:** `quality-advisory.yml`'s `pipx install ruff` fallback installs *unpinned* ruff
instead of failing closed, and `constraints.lock` is `sed`-scraped for a `ruff==` pin that — unlike
`packaging==` — has **no PR-time canary test**. Both are recorded here; neither closes a Scorecard alert.

## Amendment — 2026-08-01: zizmor `archived-uses` on the CLA action (accepted residual)

Adopting zizmor 1.28.0 (from 1.5.2) turned on audits the old pin could not run. Four of the five
findings against the otherwise-unchanged tree were resolved in-tree or as justified non-findings; this
one is an accepted residual.

* **Finding.** `warning[archived-uses]`, `.github/workflows/cla.yml:44` —
`contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1`. Upstream is
archived (API `archived: true`, `archived_at: null`; last push 2026-03-23) and v2.6.1 is the final
release. The pin equals that tag's commit exactly, so there is no later patch to move to.
* **Compensating control, and its limit.** The full-SHA pin closes tampering: a bundled JS action's SHA
fully determines the bytes that run, and a vanished namespace fails the step rather than running
someone else's code. It does not close the unpatched-code axis the audit names.
* **Why not replaced now.** `cla` is a required status context and is the job's own conclusion, so a
broken step blocks every PR. `pull_request_target`/`issue_comment` workflows run only from the default
branch, so a replacement cannot be exercised on the PR that makes it — it lands on `main` untested,
with `required_approving_review_count: 0` and auto-merge armed.
* **Hard revisit: before Node20 removal.** `action.yml` at the pin — and at the archived HEAD — declares
`runs.using: node20`. An archived repo can never re-declare node24, so GitHub's fall-2026 Node20
removal, not this lint, forces fork-or-replace. No firm date is published; treat mid-September 2026 as
the planning date and re-check before then.
* **Contingency, verified 2026-08-01.** There is no canonical successor — the archived README directs
users to fork. The best candidate found is `iainmcgin/cla-github-action`, Apache-2.0, not archived,
last pushed 2026-06-17, 4 stars, single personal maintainer. Note v3.2.0 is an **annotated** tag whose
ref resolves to tag object `07f1588b0cee15f89a489a77704c9d45d39ec0a1`; the commit `uses:` must pin is
`0d27e5a16278d4adb6b0c4b92f08ad27b0a21dc8` (dereferenced and confirmed, not assumed). Adoption is
gated on at least: accounting for the shipped `dist/index.js` (a built bundle that is not
human-reviewable, and a source review does not prove `dist/` was built from it); confirming
`signatures/version1/cla.json` stays format-compatible; verifying the inputs `cla.yml` passes still
exist with the same semantics; a decision on `require-opener-as-author`, which defaults to true and
fails the check; and a rehearsal in a scratch repo. Land in a low-traffic window with a revert
prepared.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ messagefoundry-tray = "messagefoundry.tray.__main__:main"
ci-scanners = [
"bandit==1.9.4",
"pip-audit==2.10.1",
"zizmor==1.5.2",
"zizmor==1.28.0",
]
# The ADVISORY measurement tools (quality-advisory.yml). Exact where something PARSES the tool's
# output, a floor where nothing does:
Expand Down
12 changes: 6 additions & 6 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@ elementpath==5.1.3 \
--hash=sha256:35e98cc2e26332305a49b32eaaebfb7289d1963c88d3989ff5ccb02c46809820 \
--hash=sha256:c46f5e0e36c149b892308843e1e394bdee17ceafbc18cfa39250403dd8475a4e
# via xmlschema
fastapi==0.139.2 \
--hash=sha256:333145a6891e9b5b3cfceb69baf817e8240cde4d4588ae5a10bf56ffacb6255e \
--hash=sha256:b9ad015a835173d59865e2f5d8296fbc2b317bf56a2ba1a5bfbdd03de2fd4b1c
fastapi==0.140.4 \
--hash=sha256:4a040c5d047486a62c497eb6e926a6d6b281efb7f99b8b50288489ba1fa0a468 \
--hash=sha256:6a1f8ec2f01ae47c96dc991d49660ce4f31f50ed0d7c9df80c5e57037bfe1240
# via messagefoundry
fhir-core==1.1.9 \
--hash=sha256:61f23a711199d8d74390fd473cc5ddf75a1f4def97fd8e9f59a28bc9d5222261 \
Expand Down Expand Up @@ -570,9 +570,9 @@ pluggy==1.6.0 \
--hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
# via pytest
prometheus-client==0.25.0 \
--hash=sha256:5e373b75c31afb3c86f1a52fa1ad470c9aace18082d39ec0d2f918d11cc9ba28 \
--hash=sha256:d5aec89e349a6ec230805d0df882f3807f74fd6c1a2fa86864e3c2279059fed1
prometheus-client==0.26.0 \
--hash=sha256:04a91bcf94e2cf74a44a1a874d651a2e853ed354b6e822f3b7487751465d5c2b \
--hash=sha256:fa93d06737aa02bacd05794768508bb97d2fbee28cb3bca04eaae92f0ca953d6
# via messagefoundry
protobuf==6.33.6 \
--hash=sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326 \
Expand Down
Loading
Loading