Repository navigation
Bump actions/upload-artifact from 7.0.1 to 7.0.2 - #34
Merged
kikashy merged 7 commits intoOct 27, 2026
Merged
Conversation
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.1 to 7.0.2. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@043fb46...cf430e0) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
kikashy
added a commit
that referenced
this pull request
Oct 26, 2026
…ndent checks, keep the tag-context run for the rest, fail closed (#38) (#44) Closes #38. Its "Required evidence gate" list is the acceptance contract. Milestone v0.3.0 (tooling). One review round: release admission is a trust boundary. ## Summary A release no longer runs the whole check list twice more at the tag (once from the tag push's own CI run, once from the release's call). It now does two things in order: 1. **Reuses main's evidence for the checks that read the tree.** The release takes the evidence main's push CI recorded at the **exact** release commit for `local-paths`, `agent-docs` and `diff-check`. It does this through the development kit's release evidence gate (devkit v0.10.0, vendored as `scripts/dev/release_evidence.py`, configured by `.github/ci-evidence.json`) in a new job, `CI evidence at the tag`. Any refusal fails that job, names the code and stops the release. 2. **Runs the `entries` tests again in the tag's context.** These tests read the tags and the release history (`release_being_made()` and the tag listing in `tests/test_entries.py`), and the release's tag changes both. So the release still runs them at the tag, after the gate: `CI at the tag` calls the commit's `ci.yml` with `tag-context: true`. The checkout still has the whole history and tags, the specification is still at the pin, and no verifier test is skipped. That call is now the only run in the tag's context. `ci.yml`'s `push` trigger is limited to branches, so a tag push no longer starts a duplicate run that gates nothing. Every release-specific check stays exactly as it was and in the same order: tag grammar (shell and `release_tag_ok`), tag names the commit, commit on main, notes, environment reviewer, manifest blob bytes, checksums, attestation, no existing release, draft identity, notes and asset digests, published digests. The required `entries` status keeps its name (the job now says `name: entries` explicitly, which gives the same check name). Branch protection, review and publication requirements are unchanged. ### Public surface changes - `ci.yml` gains a `workflow_call` input `tag-context` (boolean, default `false`). A push now runs its list in two parts: the tree checks, whose summary block is the evidence log, then `HISTORY_CHECKS` (`entries`). A failure in the first part does not stop the second. On a push to main it then runs `release_evidence.py capture` and uploads `ci-evidence-ci-entries-<attempt>` (7 days). - `ci.yml` no longer runs on a tag push (`push: branches: ["**"]`). Branch pushes and pull requests run as before. - `release.yml` gains the `evidence` job (`CI evidence at the tag`, `contents: read`, `actions: read`). `verify` (`CI at the tag`) needs it, and `package` needs both. The decision record is in the step log and in the `release-evidence-<attempt>` artifact, uploaded on reuse and on refusal (`!cancelled()`). - **New release precondition:** main's CI run at the commit must have completed (`run-unfinished` otherwise), must be under 48 h old, and must have run on the runner image the release job resolves. The tag must be annotated; `git tag -s`, which `docs/releasing.md` already prescribes, makes an annotated tag, and v0.1.0 to v0.2.1 are all annotated. ## Inventory: three executions at a release commit | Check | Main push CI (before the tag) | Tag-push CI (before) | Release-called CI (before) | After this PR | | --- | --- | --- | --- | --- | | `local-paths`, `agent-docs`, `diff-check` (read the commit's tree only) | run | run | run | main: run **and recorded**. Release: **reused** from main's evidence at the exact commit | | `entries` (the unittest suite: reads `GITHUB_REF`'s release tag, the tag listing below it, the earlier releases' blobs, and the specification at the pin) | run with no release being made and the tags present then | run at the tag | run at the tag | main: run, not recorded as evidence. Release: **run once, fresh, at the tag** (`CI at the tag`, `tag-context: true`) | | setup (`python-deps`, an empty requirements file) | run | run | run | main: run. Release: run before `entries` | | tag, notes, environment reviewer, manifest bytes, checksums, attestation, draft/published identity | not run | not run | release.yml, run | release.yml, run, unchanged | Main's evidence and the release's tag-context run do not overlap. A test holds the configuration's reused checks plus `HISTORY_CHECKS` to exactly `dev.json`'s checks, with no check in both. The tag-push run was equivalent to the release's call: same commit, same `refs/tags/<tag>` ref (so the same `release_being_made()`), same full-history checkout, same pinned specification, started by the same push. Its result gated nothing. The release's call now covers every check it ran, which is the issue's condition for suppressing tag CI. **Branch CI is not changed.** A branch push (whole list, at the head commit) and a pull request run (the `--changed` selection, at the synthetic merge commit) have different commits and selections, so they are not equivalent executions. A branch without a pull request has only the push run. **Toolchain and inputs.** There is one profile, `linux`, under `compare: release-runner`. The release job resolves the image (`ImageOS`, `ImageVersion`, `/etc/os-release`) and `bash`, `git`, `cmp` and `python3` itself, and they must equal main's. CI runs the checks with setup-python's 3.12 (3.12.15 from the runner's tool cache, not the image's own `python3`), so the evidence job sets Python up with the same two steps as `ci.yml`, and a test holds the two to the same text. Recorded inputs: `dev.json`, the configuration, the gate, `ci.yml` (which also holds the specification pin), `requirements-dev.txt`, `scripts/dev/check.sh` and `scripts/sync-agent-docs.sh`. Permitted skips: none (no conditional job, no optional check skip). Trusted event: `push` to main only; this repository does not dispatch CI. ## Fresh route (documented in `docs/releasing.md`) A refusal stops the run, and nothing runs CI again on its own. The operator picks one route, once: 1. Re-run all jobs of main's CI run at the commit. This is also the route for `run-age` and for a hosted image that changed (`runtime-identity`). For `run-unfinished`, wait for main's run instead. 2. When that run has completed, re-run the release run's failed jobs. 3. If the gate refuses again: fix on main and release a new version. ## Live probe (read-only API) `probe.py` walks real runs through the vendored gate's `decide()` with this configuration, using GET calls only. Three things are stubbed: - the release tag, since no tag exists at the probed commits: an annotated tag object naming the commit; - the runner identity, with this machine standing in for both runners; - in the first walk only, the evidence artifact. Main's `ci.yml` does not capture until this PR merges, so the probe builds the artifact with the gate's own `evidence()`. It uses the real run's ids, the real job interval, and the real `PASS` rows of that job's log for the three tree checks. | Walk | Commit | Live reads | Decision | | --- | --- | --- | --- | | Latest main CI run 40395182182 (push, attempt 1), evidence artifact synthesized | `6398ed8` | repository and default branch; workflow `ci.yml` resolved (id 384594220, name `CI`, active); runs at the commit: 1, applicable 1; run identity; attempt-1 jobs (`entries`, success, `ubuntu-latest`, hosted group 0); re-read of the run; re-selection twice | **`reuse`** (run 40395182182 attempt 1, age 0.92 h) | | The same run, no stub for the artifact | `6398ed8` | the same, then the real artifact listing | `refuse: artifact-coverage` (0 artifacts named `ci-evidence-ci-entries-1`: main records no evidence before this merges) | | PR #43 head (pull_request run 40390714808, branch push run 40390706439) | `88cbf53` | runs at the commit: 2, applicable 0 | **`refuse: run-missing`** | | The same two runs handed directly to the gate's run identity check | `88cbf53` | each run read by id | `run-trigger` for both | The first live `capture` is the first main push after merge. A capture refusal there fails main's `entries` job visibly. The first live `verify` is the next release. Locally, `capture` with this configuration, given the real `check.sh --all --skip entries` summary of this head, records `{agent-docs, diff-check, local-paths: PASS}` and the seven input ids. ## Tests and mutants `tests/test_release_evidence.py` adds 15 tests. They run inside the `entries` check, both at main and at the tag: - The configuration passes the gate's own `check_config`. - Every input is a file of the tree. - The workflow is `ci.yml` by path and `name:`, with `push` only and no skipped jobs. - Every required job is a job of `ci.yml`, on its labels, with no matrix and no job-level `if`. - The reused checks plus `HISTORY_CHECKS` equal `dev.json`'s checks, with none in both. - A handwritten `check.sh` summary block is read by the gate's own `coverage()`. The three rows are accepted. Adding `entries`, dropping a check, or a `SKIP` each refuses. - `ci.yml`'s capture and upload run on a push to main after the checks, from the tee'd log. - `release.yml`'s gate needs `admit`, has `actions: read`, has no `continue-on-error`, and keeps its record on refusal. - The gate job sets up Python as `ci.yml` does. - `CI at the tag` needs the gate and passes `tag-context: true`, and `package` needs both. - `ci.yml` has no tag trigger. - The vendored copy: line 2 names v0.10.0, the rest has the git blob id of the kit's `lib/release_evidence.py` at v0.10.0 (`d00e4d48…`, checked against the kit's tag), and the four vendored scripts name one kit release. The kit's 85 gate tests are not copied: the copy is held byte for byte instead. | Mutant (scratch copy of the head, one safeguard broken) | Caught by | | --- | --- | | M01 the configuration's job name drifts from `ci.yml` | `test_every_required_job_is_a_job_of_ci_yml_on_its_labels` | | M02 an input path that does not exist | `test_every_input_path_is_a_file_of_the_tree` | | M03 `entries` added to the reused checks | `…_dev_json_split_in_two`, `test_the_evidence_log_is_read_as_the_gate_reads_it` | | M04 reused checks `"all"` | the same two | | M05 the vendored gate changed after line 2 | `test_the_rest_is_the_kits_file_byte_for_byte` | | M06 line 2 names another release | `test_line_two_names_the_kit_release`, `test_the_vendored_scripts_name_one_kit_release` | | M07 `ci.yml` runs on a tag push again | `test_a_tag_push_starts_no_second_run_at_the_tag` | | M08 `ci.yml`'s job display name drifts | `test_every_required_job_is_a_job_of_ci_yml_on_its_labels` | | M09 the push path drops the history checks | `test_ci_records_the_evidence_on_a_push_to_main_after_the_checks` | | M10 capture on every push, not only main | the same | | M11 `HISTORY_CHECKS` emptied | `…_dev_json_split_in_two` | | M12 the release calls `ci.yml` for the whole list | `test_the_tag_context_run_follows_the_gate_and_the_package_waits_for_both` | | M13 no decision record on a refusal | `test_the_gate_runs_after_admission_and_keeps_its_record` | | M14 `package` no longer needs the gate | `test_the_tag_context_run_follows_…` | | M15 the tag-context run no longer needs the gate | the same | | M16 `continue-on-error` on the gate step | `test_the_gate_runs_after_admission_and_keeps_its_record` | | M17 the gate job without CI's Python | `test_the_gate_sets_up_the_python_ci_yml_ran_with` | | M18 the evidence log no longer the checks' output | `test_ci_records_the_evidence_on_a_push_to_main_after_the_checks` | All 18 were caught, and the unmutated head passes. actionlint 1.7.12 on both workflows reports one finding, SC2034 (`attempt` unused) in the unchanged draft step, which is the same on main. ## Measured before, expected after Durations are from the API, job start to completion. | Release | Main push CI `entries` | Tag-push CI `entries` | `CI at the tag / entries` | Admit end to package start | | --- | --- | --- | --- | --- | | v0.2.1 (run 39175705155) | 12 s (run 39175678865) | 14 s (run 39175705135) | 13 s | 34 s | | v0.2.0 (run 39070293785) | 17 s (run 39070265083) | 14 s (run 39070293773) | 12 s | 17 s | On the latest main run (40395182182), the three tree checks report `0s` each, `entries` 3 s, and the job takes 13 s, mostly checkout and setup. After this PR, a release has one fewer full CI run (the tag-push run, about 14 s), and the release's call drops three checks that each take under a second. In exchange it adds the gate job, which runs before the tag-context run. The kit measured its earlier gate job at 14–15 s (v0.8.0, v0.9.0). This gate reads one more repository object and sets up Python, so a similar cost is expected, but that is not measured here. **No saving is claimed.** Total runner time at a release is expected to stay about the same. The release's own critical path is expected to grow by about the gate job's duration, because the gate runs first, as the brief orders. What changes is that two tag-context runs become one, and an exact-commit decision record now exists. The first real numbers come at the next release. A refusal adds the fresh route's re-run. ## Not changed / not verifiable before merge - This PR's CI does not exercise `capture`, because it runs only on a push to main. The first push after merge will. - `verify` is first live at the next release. - `update-branches.yml` is not changed. - Dependabot #34 (upload-artifact 7.0.2) will need a rebase to cover the two new uses of the 7.0.1 pin. ## Checks Head `134100a`, `jpdev check --changed` against `origin/main` (merge base `6398ed8`; `jpdev.json` changed, so the whole list ran), with `.spec/` at the pin: ```text == check summary (dev.json) == handover: boundary 1 paths, shared 2 paths; see AGENTS.md "Before you hand over" PASS local-paths 0s PASS agent-docs 0s sync-agent-docs: CLAUDE.md matches AGENTS.md PASS diff-check 0s PASS entries 6s, python .venv/bin/python3 (Python 3.12.11) Ran 153 tests in 6.538s OK (skipped=3) == 4 passed, 0 failed, 0 skipped, 0 not run == ``` The handover self-check against `origin/main` passed: the boundary path `scripts` gains only a new file. ## Fix round This round answers the [review record](#44 (comment)) at `134100a` (0 HIGH, 2 MEDIUM, 2 LOW) in one commit, `15ff65e`. | Finding | Fix | Safeguard removed in a scratch copy, then caught by | | --- | --- | --- | | MEDIUM 1: nothing held the three reused checks to the tree | `ReusedChecksReadTheTree`: the `dev.json` commands of `local-paths`, `agent-docs` and `diff-check` are pinned in the test (shell toolchain, no `cwd`/`requires_env`), so editing one means classifying it again. Each command, and the repository script it runs (`scripts/sync-agent-docs.sh`, which runs no other), is scanned for a read of a tag, the run's ref or the history or `.spec` (`git tag`/`describe`/`log`/`rev-list`/`for-each-ref`/`ls-remote`/`show-ref`/`cat-file`/`show`/`merge-base`/`fetch`..., `GITHUB_`, `refs/tags/`, `HEAD~`). The scan has its own handwritten vectors | R1 (diff-check reads `git tag --points-at`), R1b (local-paths branches on `$GITHUB_REF`), R1c (pin and command both moved to `git describe`), R1d (`git log` in `sync-agent-docs.sh`), R1e (the script runs another repository script): all caught | | MEDIUM 2: fail-closed was held only through `needs:` | `test_no_job_after_the_gate_can_run_past_a_refusal`: the release's jobs are exactly admit, evidence, verify, package, attest-and-draft and publish. None has a job-level `if:` or `continue-on-error`, and each after the gate needs `evidence` directly or through the jobs it needs | R3 (`package` `if: ${{ always() }}`), R3b (`verify` `if: ${{ !cancelled() }}`), R3c (`publish` `continue-on-error`), R3d (`attest-and-draft` needs `admit` only): all caught | | LOW 3: `release_being_made` docstring named a tag push | now "release.yml calling ci.yml at the tag" | | | LOW 4: stale "image python 3.12.3" in this body | corrected above: both jobs set up 3.12.15 from the runner's tool cache | | Mutants this round: 9 of 9 caught, and the unmutated head passes. `tests/test_release_evidence.py` now has 19 tests. Head `15ff65e`, `jpdev check --changed` against `origin/main`, which ran the whole list because `jpdev.json` changed: ```text == check summary (dev.json) == handover: boundary 1 paths, shared 2 paths; see AGENTS.md "Before you hand over" PASS local-paths 0s PASS agent-docs 0s sync-agent-docs: CLAUDE.md matches AGENTS.md PASS diff-check 0s PASS entries 7s, python .venv/bin/python3 (Python 3.12.11) Ran 157 tests in 7.000s OK (skipped=3) == 4 passed, 0 failed, 0 skipped, 0 not run == ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kikashy
deleted the
dependabot/github_actions/actions/upload-artifact-7.0.2
branch
October 27, 2026 11:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps actions/upload-artifact from 7.0.1 to 7.0.2.
Release notes
Sourced from actions/upload-artifact's releases.
Commits
cf430e0Merge pull request #822 from actions/tunc-d-prepare-upload-v7-0-2c2acdedchore: prepare v7.0.2 release4687c1bMerge pull request #821 from actions/tunc-d-upload-artifact-package-bump8cbe1beBump@actions/artifactto 6.3.1Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)