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>
123 lines
4.8 KiB
Markdown
123 lines
4.8 KiB
Markdown
# ADR 014 — Pin actions/upload-artifact to v3 (Gitea act_runner v4 protocol incompatibility)
|
|
|
|
**Status:** Accepted
|
|
**Date:** 2026-05-14
|
|
**Issues:** [#557 — re-regression](https://git.raddatz.cloud/marcel/familienarchiv/issues/557) · [#14 — original incident](https://git.raddatz.cloud/marcel/familienarchiv/issues/14)
|
|
|
|
---
|
|
|
|
## 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:
|
|
|
|
```yaml
|
|
# 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.
|