Files
familienarchiv/docs/adr/014-upload-artifact-v3-pin.md
Marcel e17f4110f1 docs(adr-014): record upload-artifact v3 pin and Gitea act_runner v4 limitation
Documents the three-incident history, the enforcement layers (inline
comments + grep guard + ADR), how to spot the symptom, and the explicit
upgrade trigger (act_runner v4 protocol support OR v3 CVE).

Cross-references ADR-011 (single-tenant Gitea runner) and #557.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 10:58:19 +02:00

4.8 KiB

ADR 014 — Pin actions/upload-artifact to v3 (Gitea act_runner v4 protocol incompatibility)

Status: Accepted
Date: 2026-05-14
Issues: #557 — re-regression · #14 — original incident


Context

actions/upload-artifact is available in two incompatible major versions. The v4 client uploads via a GitHub-specific artifact API that is not implemented in Gitea's act_runner (the self-hosted CI substrate established by ADR-011). When a workflow step uses actions/upload-artifact@v4 on this runner, act_runner returns a non-zero exit code from the v4 client even when all tests pass, producing:

green test suite — red job status — no artifact uploaded

The failure lands in the upload step, after the test output, making it hard to diagnose from the build log.

Incident history

Date Commit Event
2026-03-19 9f3f022e Original downgrade: upload-artifact@v4 → v3
2026-03-19 4142c7cd Rationale committed; closes #14
2026-05-05 410b91e2 Re-regression: upgraded back to v4 without referencing #14
2026-05-14 this PR Second downgrade + ADR + grep guard

The root cause of the re-regression was institutional-memory failure: the original rationale was captured only in a commit body, invisible at the point of change (the uses: line). This ADR, the inline comments, and the grep guard are the three defence layers that replace that missing breadcrumb.


Decision

Pin all actions/upload-artifact and actions/download-artifact call sites to @v3.

Both action families share the same v4 protocol incompatibility with act_runner. Pinning to the major tag (@v3) keeps us on the latest v3 patch without Renovate noise.

Three call sites are pinned:

  • .gitea/workflows/ci.yml — "Upload coverage reports" step
  • .gitea/workflows/ci.yml — "Upload screenshots" step
  • .gitea/workflows/coverage-flake-probe.yml — "Upload coverage log on failure" step

Each pinned uses: line carries a load-bearing inline comment:

# Gitea Actions (act_runner) does not implement upload-artifact v4 protocol — pinned per ADR-014. Do NOT upgrade. See #557.
- uses: actions/upload-artifact@v3

A CI grep guard enforces the constraint automatically (see below).


Consequences

Enforcement layers (defence in depth)

  1. Inline comments on every uses: line — visible at the point of change.
  2. CI grep guard in .gitea/workflows/ci.yml ("Assert no (upload|download)-artifact past v3") — fails the build if a future commit re-introduces @v4 or higher on any workflow file. Anchored to YAML uses: lines to avoid false positives on embedded shell strings. Includes a self-test that proves the regex catches v4+ before scanning the repo.
  3. This ADR — canonical rationale; cross-referenced by comments and guard message.

How to spot the symptom

  • Test suite output shows green (vitest, surefire, pytest all exit 0)
  • CI job status shows red
  • Artifacts section of the run is empty
  • Build log shows a non-zero exit from the Upload … step immediately after green tests

@v3 maintenance-mode status

GitHub placed actions/upload-artifact@v3 in maintenance mode (no new features) but it has not been removed and carries no known unpatched CVE as of this writing. If GitHub publishes a v3-specific security advisory, that is an additional trigger to re-evaluate (see upgrade conditions below).

When to remove this pin

Re-evaluate pinning when either condition is met:

  1. gitea/act_runner ships a release with v4 artifact protocol support. Track upstream: https://gitea.com/gitea/act_runner
  2. actions/upload-artifact@v3 acquires an unpatched CVE that cannot be mitigated at the runner level.

When upgrading: remove the grep guard step, update all three uses: lines, remove the inline comments, and update this ADR's status to Superseded.


Alternatives

SHA pinning (uses: actions/upload-artifact@<sha>)

More secure against action repository compromise, but adds Renovate update friction and is disproportionate for a self-hosted, single-tenant Gitea instance with one trusted contributor (ADR-011). Rejected.

Minor/patch pinning (@v3.4.0)

Avoids Renovate PRs but freezes us on a specific patch. The v3 major track is in maintenance mode — minor pinning has no benefit and would require manual updates for any v3 security patches. Rejected.

Renovate packageRules bypass

Would prevent automated PRs from proposing v4. Not needed while Renovate is not configured for this repository. Revisit if Renovate is introduced.

Migrating the runner to a v4-compatible Gitea release

Out of scope for this issue. A separate decision; tracked in #557's non-goals.