Files
vac-optimizer/docs/gitea-actions.md
T
nessarandClaude Opus 5.5 d9c7f72461
CI / policy (push) Successful in 8s
CI / build (push) Successful in 40s
CI / security (push) Successful in 1m44s
CI / policy (pull_request) Successful in 10s
CI / test (push) Successful in 3m6s
CI / validate (pull_request) Successful in 39s
CI / test (pull_request) Successful in 5m18s
CI / benchmark (push) Successful in 9m44s
CI / build (pull_request) Successful in 1m33s
CI / security (pull_request) Successful in 1m1s
CI / benchmark (pull_request) Successful in 7m56s
CI / validate (push) Successful in 11m34s
CI / images (pull_request) Successful in 2m42s
CI / required (pull_request) Successful in 1s
CI / images (push) Successful in 1m25s
CI / required (push) Successful in 5s
docs(ci): note the Docker 29.9.1 image
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:24:11 +02:00

178 lines
13 KiB
Markdown

# Gitea Actions conversion
[Issue #268](https://gitea.nessar.fr/nessar/vac-optimizer/issues/268) converts the
repository's CI to [`.gitea/workflows/ci.yml`](../.gitea/workflows/ci.yml).
The workflow and merge-message template have passed implementation review.
Repository Actions is enabled with owner approval. Publisher credentials and
live workflow validation are still pending.
The existing `gitlab-to-gitea/ci-conversion-required` status stays in place until
that review, a successful Gitea PR run, and approval of the prepared first merge
message.
## Jobs and triggers
Every branch and tag push runs CI. Pull requests run on opening, reopening,
synchronization, and title/body edits. Manual dispatch runs validation without
publishing images. There is no schedule or deployment job in the preserved
configuration; the Compose files remain manual deployment options.
| Job | Behavior |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `policy` | Tests the policy and publisher with Bun, then validates the checked-out commit, GitFlow, PR title, commits, and stable release version. |
| `validate` | Runs ESLint, Prettier (application, `scripts/ci-*.mjs` and workflow files) and `bun check` type checks of application and test code, all on Bun with the frozen lockfile. |
| `test` | Runs functional coverage with `bun test --isolate` (line coverage only), converts it to HTML and Cobertura, and uploads coverage for seven days even on failure. |
| `benchmark` | Required seven-scenario protocol (one warm-up, two measured repetitions) outside coverage in a container limited to 3 GiB. It first times the frozen engine on `two years` (best of three) and fails any scenario whose mean planning time exceeds its multiplier times that calibration; the 600-second timeout is only a hang guard. |
| `build` | Builds the client-only Angular production bundle (the only check of Angular templates; `bun check` does not replace it) and the Bun static-server bundle, and retains `dist` for seven days. |
| `security` | Runs Semgrep JavaScript/TypeScript SAST and Trivy dependency/secret scans; retains SARIF reports for seven days. Scanner execution must succeed; findings remain reports rather than a new severity gate. The scanners are not project JavaScript, so this job installs no Bun. |
| `images` | Publishes branch/SHA images after required validation, including the benchmark, or promotes an existing SHA image for a stable tag, running the publisher with Bun. Runs only for pushes and same-repository PRs. |
| `required` | Fails on failed, cancelled, or skipped required validation, including the benchmark. Requires image publication when expected; accepts its intentional skip for fork PRs and manual dispatch. It is shell only and needs no Bun. |
The benchmark runs on both push and pull_request events: the push run gates image
publication (`images.needs` includes `benchmark`) and the `required` aggregate.
The relative gate absorbs a slower runner and load that lasts through the whole
job, because calibration runs in the same job. It does not absorb load that
starts or stops during the protocol, such as an overlapping push and
pull_request run of the same commit; the 600-second hang guard still bounds
those runs.
Push and PR runs are separate so PR title and rebase checks run on the PR event.
New runs cancel older runs for the same event/ref. Image jobs serialize per
branch slug; stable promotions share one group and are not cancelled in progress.
## Runners and permissions
Every job that runs project commands uses Bun 1.4.3 with the frozen lockfile (see [Bun toolchain and Node](#bun-toolchain-and-node)). Job containers stay on Node 24.21.0. The image
job uses Docker 29.9.1 and its matching Docker-in-Docker service. Scanner
versions are Semgrep 1.180.0 and Trivy 0.75.0; Trivy downloads are checksum-checked.
Trivy downloads its vulnerability database from Aqua's public ECR mirror because
the default registries returned a missing database blob and a download timeout.
Jobs select the `ubuntu-latest` label and require Linux container-job support.
Allow at least the benchmark job's 3 GiB container memory limit plus runner overhead.
The instance currently has an online inherited runner named `srvhome`, labelled
`ubuntu-latest` and `ubuntu-24.04`. Repository runners, secrets, and variables
were empty at implementation time. The owner must verify that this runner can
run the job containers, JavaScript actions, artifact uploads, and the privileged
Docker-in-Docker service before replacing the migration gate. Use isolated runners for untrusted
contributor code; the privileged publishing service belongs to trusted runs.
The workflow requests a read-only repository token. Checkout removes persisted
credentials; publication credentials are passed only to the image step. Fork PRs
and manual dispatches cannot run that step. Gitea's job token cannot publish
container packages, so provision the two repository Actions secrets below.
See [job-token permissions](https://docs.gitea.com/usage/actions/token-permissions/)
and [package authorization](https://docs.gitea.com/usage/actions/comparison/).
| Secret | Purpose |
| ------------------- | --------------------------------------------------------------------------- |
| `REGISTRY_USERNAME` | The package publisher's Gitea username, authorized to publish for `nessar`. |
| `REGISTRY_PASSWORD` | A dedicated personal access token with `write:package` permission. |
Keep secret values in Gitea's Actions secret store. The configured tea account's
administrator token is not a CI publishing credential. No SSH or deployment
secret is required by this workflow.
## Bun toolchain and Node
Project commands run on Bun 1.4.3 only. `package.json` (`packageManager`),
`@types/bun`, both Docker stages and `scripts/install-bun.sh` carry the same
version. To upgrade, change all of them together and replace the installer's
four SHA-256 values with those of the new release's `SHASUMS256.txt`; the
installer refuses a `package.json` that names a different version, so a bump of
only one place fails CI instead of drifting.
- **Install.** `policy`, `validate`, `test`, `benchmark`, `build` and `images`
run `sh scripts/install-bun.sh`. It downloads the release zip for the
runner's architecture (x64 or aarch64) and libc (glibc, or musl on Alpine),
verifies its pinned SHA-256, and installs `/opt/bun/bin/bun`. It uses no npm.
- **Node-free project steps.** The five Debian jobs set
`defaults.run.shell: env PATH=/opt/bun/bin:/usr/bin:/bin bash -e {0}`. Every
`run:` step then sees Bun but not `/usr/local/bin`, where the `node` image keeps
`node`, `npm` and `yarn`. `bun run` additionally runs Node-shebang tools on Bun
through `bunfig.toml`. The security scanners are not project JavaScript, so
`security` has no Bun and no custom shell.
- **Why the containers keep Node.** `actions/checkout@v4` (`node20`) and
`actions/upload-artifact@v3` (`node16`) are JavaScript actions. The runner
starts them with the container's `node`; the custom shell does not affect
`uses:` steps. This is a platform requirement, not permission to run project
commands on Node.
- **`images` exception.** Alpine's `nodejs` package installs `node` into
`/usr/bin`, beside `git`, and checkout's post step needs it, so `PATH` cannot
hide it there. The project command is `/opt/bun/bin/bun scripts/ci-image.mjs`;
it starts only `process.execPath`, `docker` and `git`. Hiding Node there needs
an infrastructure decision (for example a runner image that ships Node outside
`PATH`), which this conversion does not make.
- **Needs live validation.** The custom shell template is a GitHub Actions
feature that Gitea's runner implements. A local run of the real engine
(`gitea-runner exec` v5.1.0, with the job containers above) executed it, but
only a live Gitea run confirms the instance's runner version, the checkout
action and the privileged Docker-in-Docker `images` job.
## Images and releases
Images use the [Gitea container registry](https://docs.gitea.com/usage/packages/container/)
at `gitea.nessar.fr/nessar/vac-optimizer`. Branch pushes and same-repository PRs
publish `branch-<slug>` and `sha-<full commit SHA>`. Slugs retain the previous
lowercase, non-alphanumeric-to-hyphen, 63-byte normalization; choose distinct
branch slugs.
Only stable `vX.Y.Z` tags matching the tagged commit's `package.json` version
and reachable from `main` may promote images. Promotion first pulls the existing
SHA image, then publishes the version tag and `latest`; it never rebuilds.
An absent SHA image fails before either stable tag changes. Wait for the main
image job before tagging. No version increment or deployment is automatic.
## Merge messages and activation
The [merge template](../.gitea/default_merge_message/MERGE_TEMPLATE.md) translates
the previous title, closing-issue references, and review reference using
[Gitea's supported variables](https://docs.gitea.com/usage/issues-prs/merge-message-templates/).
For a PR titled `ci: migrate to Gitea Actions`, closing #268, with reference #271,
the checked expansion is:
```text
ci: migrate to Gitea Actions
close #268
See pull request #271
```
The owner has enabled Actions and approved validation before adding publisher
secrets. Complete the remaining activation checks in this order:
1. Review this workflow against the protected administrator exports for runner
requirements, triggers/schedules, permissions, secrets, publishing, and
deployment dependencies. The original CI definition is retained in Git:
`git show 0d900fd72d1a405d257f5a566c55cc0cb3d2bc61:.gitlab-ci.yml`.
2. Publish the reviewed feature branch and open its PR to register the workflow.
Once registered, manual dispatch verifies validation and artifacts without
publishing images. Push and PR validation can also run now; their image and
aggregate checks remain blocked until publisher secrets are provisioned.
3. Verify runner isolation and Docker service support, then provision the two
publisher secrets. Review the package publisher's permissions and registry
namespace before permitting publication. Rerun the PR workflow and require a
successful **pull-request run** on the final commit, including PR title and
rebase checks, artifact handling, and actual image publication. A push run
or manual run alone does not validate the PR policy and publication.
4. Prepare and review the first PR's merge message before replacing the migration
gate. The target branch will not contain the new template until that first
merge, so explicitly use the validated PR title, closing references, and PR
reference for its merge message. Keep the migration gate throughout this
review.
5. After the successful PR run and merge-message approval, replace the migration
status requirement on both protected branches with the **actual reported
pull-request context** for the `required` job. Select it from the PR's reported
checks rather than a push run or a guessed context spelling. Fork PRs must
also be able to satisfy this check without base-repository push permissions.
Keep direct/force pushes disabled, merges restricted to maintainers, outdated
PRs blocked, and administrator protection bypass disabled. Select merge
commits and disable squash/rebase merge methods.
6. Merge the first PR using the approved message, then verify the resulting merge
commit. Subsequent merges read the committed template. No direct
integration-branch push is needed.
Historical job execution, reports, and downloadable artifacts remain in the
administrator rollback backups. They are not recreated or uploaded by this
conversion.