Commit Graph
39 Commits
Author SHA1 Message Date
Alejandro Roman 764a1adf30 feat(svc-runners): add the logic to have x numbers of runners self hosted ad connected to GIthub, allowing to have 20 runners from gh + x self hosted 2026-06-24 18:30:31 +02:00
kevinveenbirkenbachandClaude Opus 4.7 f286ce54dd fix(update/open_pr): scope dedup to changed files
The previous tree-hash dedup compared whole-commit trees, so unrelated
drift on main (e.g. a manual edit to any roles/* file) caused the same
auto-update delta to appear "new" each daily cron and a fresh PR to open.

Now: fingerprint only the files that this run actually committed
(git diff --name-only HEAD~1 HEAD), both locally and on each candidate
open PR with the same UPDATE_BRANCH_PREFIX. If any open PR carries the
identical content for those files, skip push + PR creation entirely.

Branch name now carries the fingerprint's short hash so parallel PRs
of the same class can coexist (the close-superseded loop is dropped).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 10:37:21 +02:00
kevinveenbirkenbachandClaude Opus 4.7 af628847bb fix(update/open_pr): delete head branch when closing superseded PRs
The previous gh pr close call left the bot's daily update branch
behind on the remote, so stale update/<prefix>-YYYYMMDD refs
accumulated indefinitely. --delete-branch removes the head ref on
close. Scope-safe because the loop only iterates branches matching
${UPDATE_BRANCH_PREFIX}-.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 21:06:34 +02:00
kevinveenbirkenbachandClaude Opus 4.7 dd7e84257f fix(update/open_pr): skip non-existent credentials paths via truncate -c
actions/checkout records two includeif targets per repo: one under
the host path (/home/runner/work/_temp/...) and one under the
container-internal path (/github/runner_temp/...). Only the host path
exists on the runner; the container path is a placeholder for
docker-based actions.

`truncate` (without -c) aborts on the missing container path with
exit 123. Add `-c` (--no-create) so missing paths are skipped
silently and the existing credentials file still gets blanked.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:42:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 6dc402e2b7 fix(update/open_pr): blank checkout's external credentials file
actions/checkout v6 doesn't put `http.https://github.com/.extraheader`
inside .git/config; it writes that header to an external file at
/home/runner/work/_temp/git-credentials-*.config and pulls it in via
local `includeif.gitdir:<repo>/.git.path = <credfile>` directives.
That's why every earlier `git config --local --unset-all` /
`--remove-section` round was a silent no-op (verified by the previous
debug commit's dump: the extraheader survives because the source-of-
truth lives outside .git/config).

Read every includeif `.path` value from local config, dedupe, and
`truncate -s 0` the targets so the included header chunk becomes
empty. The App installation token then enters the wire via the
URL-embedded `x-access-token:${GH_TOKEN}` credentials with no
competing Authorization header.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:37:08 +02:00
kevinveenbirkenbachandClaude Opus 4.7 86a998159b debug(update/open_pr): dump every config scope + probe token identity
The previous strip targeted only `--local` config and the resulting
CI log showed local was already empty, yet the push still authed
as github-actions[bot]. The auth has to be coming from --global,
--system, --worktree, or GH_TOKEN itself is GITHUB_TOKEN.

Dump every scope's http/credential/url entries before and after the
strip, and probe /installation/repositories with GH_TOKEN so the
HTTP status alone (no secret in logs) tells us whether it's an App
installation token or the workflow GITHUB_TOKEN.

Will replace this with the real fix once the next CI run surfaces
where the rogue Authorization actually originates.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:30:02 +02:00
kevinveenbirkenbachandClaude Opus 4.7 3dffbb8493 fix(update/open_pr): strip every extraheader via regex + log what was hit
Previous attempts targeted a specific config key path
(`http.https://github.com/.extraheader`). If actions/checkout v6
stores it under a different subsection naming, our unset/remove-section
no-ops silently and the GITHUB_TOKEN-bearing header keeps overriding
the App-token URL credentials.

Walk every `http.*.extraheader` entry the local config holds, pipe
the matched key names through xargs to unset-all each one, and dump
the remaining `http.*` config before pushing so the next CI run
proves what was stripped. The push itself still uses an
x-access-token URL so the App's installation token is the only
Authorization that reaches the wire.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:23:27 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d950770385 fix(update/open_pr): nuke checkout's http section and push via tokenised URL
`--replace-all` on http.https://github.com/.extraheader still left the
wire with two Authorization headers ("remote: Duplicate header" → 400).
Drop the existing extraheader **and** the whole `http.https://github.com/`
subsection from local config, then push to a URL that embeds
`x-access-token:${GH_TOKEN}` directly so only one Authorization header
(the App's installation token) reaches the server.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:16:10 +02:00
kevinveenbirkenbachandClaude Opus 4.7 34f0c1d6c8 fix(update/open_pr): replace checkout extraheader instead of unsetting
Last attempt (unset + URL-embedded token) still pushed as
github-actions[bot] because actions/checkout's
http.https://github.com/.extraheader Authorization survived the
unset (likely silenced by `|| true`) and outranked URL-embedded
credentials on the wire.

Force-replace the header value with the App installation token's
HTTP Basic equivalent (`x-access-token:<token>` base64'd, same shape
checkout itself uses for GITHUB_TOKEN). Drops the URL rewrite, drops
the unset-then-rewrite dance, and guarantees a single Authorization
header that GitHub honours as the App.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:08:35 +02:00
kevinveenbirkenbachandClaude Opus 4.7 ee9800200e fix(update/open_pr): suppress url-reachability lint on extraheader unset
`git config --unset-all "http.https://github.com/.extraheader"` is a
git config key path, not a fetchable URL, but
tests/external/repository/test_urls_reachable.py extracts the URL-like
substring and probes it, which returns 404 and fails the suite.

Tag the line with `# nocheck: url` so the URL test skips it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:01:36 +02:00
kevinveenbirkenbachandClaude Opus 4.7 ce30948ed4 fix(update): push update branches with the App installation token
`actions/checkout` configures git's http.extraheader to authenticate
as GITHUB_TOKEN, which update.yml scopes to `contents: read`. The
subsequent `git push --force` in open_pr.sh therefore tripped 403
("Permission to infinito-nexus/core.git denied to github-actions[bot]")
even though the token-minting step had already produced an App
installation token with `contents: write` in GH_TOKEN.

Drop checkout's extraheader and rewrite origin's URL to embed
GH_TOKEN as x-access-token before pushing, so the App's permissions
actually reach the wire.

Also pin two actionlint `-ignore` patterns in scripts/lint/action.sh
to silence false positives for the `client-id` input on
actions/create-github-app-token@v3 (the action's action.yml carries
the input and marks `app-id` deprecated; actionlint 1.7.12's bundled
schema lags behind the upstream release).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 12:47:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a988c12606 fix(update): tree-hash dedup + shellcheck SC1091 suppression
open_pr.sh's PR-dedup loop relied on `gh pr diff <num>` which the
GitHub API refuses with HTTP 406 once a PR exceeds 300 changed files.
Under `set -euo pipefail` that killed the workflow whenever any
unrelated large PR was open against the same base branch.

Replace the diff-hash check with a tree-SHA comparison: fetch each
PR's head commit shallowly, compare `git log -1 --format=%T` against
HEAD's tree. Same-tree means same end-state regardless of base SHA,
whitespace, file order, or patch context. Unfetchable heads (deleted
branches, lost permissions) fall through as non-duplicates instead of
aborting the run.

image_versions.sh / repository_refs.sh also pick up an explicit
`# shellcheck disable=SC1091` above their `. .env` source since the
dotenv file is generated at runtime and never present during
shellcheck's static parse.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 12:23:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 3537d4d0a6 fix(update): load .env before invoking python updaters
`update.yml` jobs (Docker image versions, repository refs) shelled
straight into `python3 -m cli.contributing.update.{docker,repository}`
without sourcing the project dotenv. After eb4bcd23a removed the
`.get(..., default)` fallback in resolve_max_fetch_workers(),
KeyError: 'INFINITO_WORKER_FETCH' surfaced on every run.

Both wrapper scripts now `make dotenv` (idempotent) and `set -a; . .env;
set +a` before exec'ing the updater, restoring the SPOT env chain on
CI runners that don't go through compose.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 11:26:23 +02:00
kevinveenbirkenbachandClaude Opus 4.7 c02229b4be refactor(make): align targets to domain prefixes (compose-, network-, etc.)
Apply a consistent naming convention to the Make target inventory so
every target is grouped by its domain:

- compose-*  (compose-up/down/restart/stop/exec/inner-run)
- network-*  (network-dns-setup/remove, network-ipv6-disable/restore,
              network-refresh, network-trust-ca)
- security-* (security-apparmor-restore/teardown)
- diagnose-* (diagnose-network, diagnose-disk-usage)
- fix-*      (fix-chmod, fix-dockerignore)
- clean-*    (clean-cache, clean-pycache-dirs)
- install-*  (install-agent)
- meta-*     (meta-list, meta-tree, meta-mig)

Drop the stale debug-network target and reintroduce its functionality
as diagnose-network. Cascade renames through:

- Makefile (.PHONY entries, prereqs, recursive $(MAKE) calls)
- contributor docs, agent-iteration docs, role-level docs
- bundle README, environment scripts, install/lint/test wrappers
- AGENTS.md, CLAUDE.md, compose/cache.override.yml, .github/workflows

Historical entries under docs/requirements/ and changelog/ stay
untouched as audit logs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 21:00:45 +02:00
kevinveenbirkenbachandClaude Opus 4.7 356e3366be feat(make): consolidate local deploy into single make deploy router
Replace the seven separate deploy-* make targets with a single `make
deploy` recipe that maps short Make variables to the canonical
INFINITO_* environment variables and dispatches via the new
scripts/tests/deploy/local/deploy/main.sh router. main.sh and all
sub-scripts continue to read the long-form names, so Ansible passthrough
and container forwarding stay unchanged.

Short Make CLI now exposes apps, mode, purge, type, bundles, disabled,
and full_cycle as aliases. The router picks the verb folder
(initialize, reinstall, update) and scope (all, selection) based on the
chosen mode plus the presence of INFINITO_APPS or INFINITO_BUNDLES.

Also folds in the global INFINITO_TEST_DEPLOY_TYPE -> INFINITO_DEPLOY_TYPE
rename across default.env, passthrough handler, dotenv test, CI deploy
workflows, discovery scripts, and the server stage task.

Active contributor and agent-iteration docs, role-level Administration
and README files, the bundles README, and the deploy reset helper are
all retargeted to the new short CLI. docs/requirements/ entries stay
untouched as historical audit logs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 20:22:28 +02:00
kevinveenbirkenbachandClaude Opus 4.7 ce48a8151a refactor(ci): extract images-build-ci inline blocks into runner SPOTs
Three inline `run:` blocks moved into `scripts/github/runner/`:

* `images_build_outputs.sh "$distros" "$image_tag"` — replaces the
  matrix/image_tag computation in the "Compute matrix JSON" step; emits
  both outputs to $GITHUB_OUTPUT in one call.
* `distros_matrix.sh "$distros"` — the matrix-JSON primitive
  (`split(" ") | map(select(length>0))`), reused by test-dns.yml's
  matrix step. Removes the jq duplicate that lived in both workflows.
* The two pre/post-build `Disk pressure` steps now invoke the already-
  existing `disk_pressure_report.sh PRE-BUILD` / `POST-BUILD` instead of
  duplicating the df/docker-system-df/buildx-du block inline.

Behaviour unchanged; the workflow runs the same commands via the SPOT
helpers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:01:39 +02:00
kevinveenbirkenbachandClaude Opus 4.7 9a578952c3 feat(env): SPOT env-pipeline + INFINITO_* namespace
Replace 8 bash env modules with a single Python generator
(cli.meta.env) that materialises env/static.env + runtime context
into a gitignored .env. Each variable lives in its own handler
under utils/env/handlers/; defaults carry inline one-line `# ...`
comments.

Rename to the INFINITO_* schema:
- workflow inputs: APPS, SERVICES_DISABLED, CMD, DEBUG, WHITELIST,
  BUNDLES, FULL_CYCLE, VARIANT, RUN_FLAGS, LIMIT_HOST, PARALLEL
- inventory: INVENTORY_DIR / INVENTORY_FILE / HOST_VARS_FILE,
  PW_FILE -> INVENTORY_PASSWORD_FILE
- venv: VENV_BASE / VENV_FALLBACK / VENV_NAME
- new SPOT defaults: COMPILE_SILENCE, CONTAINER_NO_CA,
  WAIT_HEALTH_TIMEOUT_S, PACKAGE_CACHE_FRONTEND_INIT_IMAGE,
  promoted IMAGE_TAG from GHA-only to general passthrough

compose.yml hardening:
- inline \${VAR:-default} removed; strict \${VAR:?...} everywhere
- new integration lint blocks regressions

Tooling:
- scripts/install/all.sh owns the stamp-file install logic
  (Makefile target delegates)
- scripts/meta/env/load.sh is the single shell entry point;
  8 bash modules deleted
- new shell lint: no INFINITO_* defaults outside env/static.env

Tests:
- 93 new unit tests for utils/env/{builder,parser,runtime,writer}
- restructure tests/lint into repository/ (file-content rules) vs
  filesystem/{shell,python,env}/ (filesystem-shape rules)
- drift + smoke integration tests against the generator

Docs:
- variables.md is now a pointer; per-variable docs live next to
  the key in env/static.env / env/ci.env
- compose.yml.md drops the Default column

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 20:40:34 +02:00
kevinveenbirkenbachandClaude Opus 4.7 da77dd063b feat(update/open-pr): dedupe across open PRs and supersede stale class siblings
Two new steps wrapped around the existing push/create flow:

1. Dedupe before push: hash the local diff vs origin/<base-branch> and
   compare against gh pr diff of every open PR (any author, any branch)
   targeting the same base. On a match, exit 0 without pushing and
   without creating a PR. This is what stops the same image-version
   bump from being opened repeatedly.

2. Supersede after create: close every other open PR whose branch
   starts with UPDATE_BRANCH_PREFIX with a "Superseded by #N." comment.
   The prefix filter keeps the bot from ever closing repository-refs,
   skills, or human-authored PRs, even though dedupe itself sees them.

CRLF normalization on both sides of the hash compare so a runner that
checks out the patch with native-CRLF translation still produces a
stable hash.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:50:26 +02:00
kevinveenbirkenbachandClaude Opus 4.7 f9147e4486 refactor(scripts/github): split helpers into responsibility subfolders
Group the shell helpers under scripts/github/ into five subfolders
that match how the workflow files consume them:

  runner/   host-runner hygiene (disk, swap, Docker daemon, diagnostics)
  cancel/   run cancellation on PR-close and branch-delete events
  resolve/  derivation of workflow inputs and outputs from repo state
  update/   scheduled Update: Versions pipeline
  release/  release-time gates

Drop the now-redundant subfolder prefix from each filename, e.g.
dump_runner_state.sh becomes dump_state.sh and cancel_pull_request_runs.sh
becomes pull_request_runs.sh. Each subfolder carries a README that
describes its scope per documentation.md rules; the top-level README
points at the subfolders without inventorying files.

Propagate the new paths through ten workflow files, three docs
(workflow.md, pipeline.md, secrets.md), and two tests. Fix a real
runtime bug in enlarge_swap.sh, which still referenced the
pre-rename dump_runner_state.sh path. Extend the inline-block-size
lint hint to describe the new subfolder convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:50:26 +02:00
kevinveenbirkenbachandClaude Opus 4.7 0b5672d7d5 ci(update): mint GitHub App token so update PRs trigger full CI
Workflow-driven update PRs opened with GITHUB_TOKEN do not start
further workflow runs, so the CI orchestrator never executed against
them. Each PR-opening job in update.yml now mints a short-lived
GitHub App installation token via actions/create-github-app-token@v2
and forwards APP_SLUG to open_update_pr.sh, which derives the
verified-commit identity from the App user.

The job-level permissions block drops to read-only since write access
is provided exclusively by the App token. Behaviour with the secrets
unset is fail-loud: the token step fails, the PR step is skipped,
and no PR with an unintended identity is ever created.

Requires the BOT_APP_ID and BOT_APP_PRIVATE_KEY repository secrets
documented in docs/contributing/tools/github/actions/secrets.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 00:50:25 +02:00
kevinveenbirkenbachandClaude Opus 4.7 98457f98fd refactor(update): unify version bumpers under utils/update + cli/contributing/update + scripts/github/update
Folds the parallel Docker-image and git-ref version-update plumbing
into a single subsystem so the auto-update workflow, the external
freshness tests, and the unit tests all share one module layout.

utils/
  update/
    base.py        # semver primitives shared by both backends
    docker.py      # OCI registry lookups + version: line rewriter
    repository.py  # git ls-remote walker + ref: line rewriter

cli/contributing/update/
  docker/           # python -m cli.contributing.update.docker
  repository/       # python -m cli.contributing.update.repository

scripts/github/update/
  image_versions.sh
  repository_refs.sh

Tests mirror the same shape under tests/{unit,external}/update/{docker,repository}/.

Also widens the Docker bump scope to all roles (previously gated on
`web-*`) so non-web roles like sys-svc-container get bumped too;
pins Bookwyrm's python image at 3.11-bookworm via
`# nocheck: docker-version` with a TODO until upstream supports
Python >= 3.12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:12:07 +02:00
kevinveenbirkenbachandClaude Opus 4.7 b1b73bc1df refactor(lint): tighten inline-script lint to 11 lines + extract overflows
Drops `MAX_LINES` from 12 to 11 in `test_inline_script_block_size.py`,
catching the five blocks that were sitting exactly on the previous
threshold. Pure-bash blocks move to dedicated `.sh` files invoked via
`ansible.builtin.script:` or `run: bash …`; the keycloak heredoc with a
templated JSON payload splits into a `set_fact` plus a folded
`printf | kcadm … -f -` one-liner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:06:32 +02:00
kevinveenbirkenbachandClaude Opus 4.7 efacb56985 refactor(cli): retire one-shot fix tools, move docker version updater
Drop four one-shot or now-redundant tools from cli/fix/:

* vars_main_files — bulk-created vars/main.yml with application_id
  per role-prefix during the SPOT migration. The schema is now
  enforced declaratively by tests/integration/roles/applications/id/
  test_matches_role_name.py and the role-mapping SPOT lint.
* move_unnecessary_dependencies — moved meta dependencies to guarded
  include_role on first sweep. Permanent enforcement lives in
  tests/integration/roles/meta/dependencies/test_unnecessary.py.
* tabs — replaced literal tab characters with two-space indentation
  in YAML files. Autoformat covers new occurrences.
* ini_py — generic helper that filled missing __init__.py files; new
  packages now ship them from the start.

Move the remaining (still-actively-used) docker version updater out
from under cli/fix/ and into cli/contributing/, where the recurring
maintenance tooling lives:

* cli/fix/docker_image_versions → cli/contributing/docker/update_versions

Update the corresponding wiring:

* scripts/github/update_docker_image_versions.sh now calls
  python -m cli.contributing.docker.update_versions
  (the entry point invoked daily by .github/workflows/update.yml).
* docs/requirements/008-role-meta-layout.md references the new path.
* PROJECT_ROOT in __init__.py drops one parents[] level (the package
  sits one folder deeper now).

cli/fix/ is fully removed; new contributor-facing tooling belongs
under cli/contributing/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:19:42 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d3afe0bc81 test(lint): forbid a file from referencing its own path as a string
Hard-coded self-path references rot the moment the file moves: a header
comment ``# utils/foo/bar.py`` at the top of a module, a docstring
mentioning ``utils/foo/bar.py``, or a docs entry linking
``utils/foo/bar.py`` from inside ``utils/foo/bar.py`` itself all silently
desync from reality after the next ``git mv``.

The new lint walks every project file, computes its POSIX-style relative
path from PROJECT_ROOT, and reports any line whose text contains that
path as a substring. Files at the repo root (no ``/`` in their relative
path) and setuptools-generated ``*.egg-info/`` artefacts are exempt.
Per-line opt-out via ``# nocheck: self-path-reference`` on the offending
line, registered in the suppression catalog.

Existing offenders cleaned up:
- 72 redundant ``# <self-path>`` header lines removed across roles,
  cli, plugins, scripts, tests, and utils.
- 4 prometheus templates that told consumers to "update
  <self-template-path>" rewritten to drop the redundant self-reference.
- 8 docstring/comment self-references in cli, plugins, tests, utils,
  and the dashboard oidc.js.j2 header rewritten to describe the layout
  without naming the file's own path.
- 17 legitimate usage examples (shell scripts, test data lists, one
  template self-include doc-block) marked with ``nocheck:
  self-path-reference``.
- ``container.sh`` heredoc usage strings switched to ``${0}`` so the
  marker stays out of the user-visible help output.
- ``healthcheck/http.yml.j2`` doc-block rewritten to prose because
  ``{# ... #}`` Jinja comments cannot host an inner ``{# nocheck #}``
  (the inner ``#}`` closes the outer comment).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 03:53:44 +02:00
kevinveenbirkenbach c0891bd40a Merge branch 'main' into feature/web-app-fediwall 2026-05-06 00:02:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 9524c50928 feat(ci): diff-driven app whitelist for deploy tests
Narrow the test-deploy-{server,universal,workstation} matrix to roles
actually impacted by the branch's diff against origin/main, expanded
transitively over run_after + dependencies + shared services.

Why: full-matrix deploy CI on every PR is wasteful; explicit per-PR
whitelisting is error-prone. The resolver derives the affected set
automatically while remaining fail-safe.

Behaviour (in resolve_effective_whitelist.sh precedence order):
- whitelist input "__ALL__"  -> empty whitelist (force full deploy)
- whitelist input non-empty  -> verbatim
- whitelist input empty      -> diff vs origin/main
  - empty diff or any path outside roles/<role>/   -> __ALL__
  - all paths under roles/<role>/                  -> reverse closure

Fail-safe: any seed that is not modellable in CombinedResolver
(no application_id and not referenced by any role's run_after) and
any resolver runtime error MUST trigger a fall-back to __ALL__.
The closure never silently shrinks the deploy matrix.

test-deploy-local.yml is intentionally exempt (local/manual dispatch
keeps explicit whitelist semantics).

Documented in pipeline.md and workflows.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 22:49:41 +02:00
kevinveenbirkenbachandClaude Opus 4.7 f3845323f1 test(lint): cap inline literal script blocks at 12 logical lines + extract offenders
Add tests/lint/repository/test_inline_script_block_size.py: scans
roles/, tasks/, playbooks/ and .github/ YAML for literal block scalars
(`|` / `|-` / `|+`) following the keys `shell`, `command`, `script`,
`raw` (Ansible) and `run` (GitHub Actions). Counts logical lines —
trailing-`\` continuations collapse to one line, blank lines are
ignored — and fails when a block exceeds 12.

FOLDED scalars (`>` / `>-` / `>+`) are exempt: they are one shell
statement after YAML folding, even if they span many source lines for
readability.

The walk goes through `utils.cache.files.iter_project_files(...)` per
`docs/agents/action/testing.md` so the shared project-tree cache is
reused across the lint suite.

The fail message tells the author exactly how to fix: Ansible tasks
get the built-in `script:` module (collapses the task to one line);
GitHub Actions workflows extract into `scripts/github/<name>.sh` and
call it via `run: bash scripts/github/<name>.sh` (or
`_helpers/scripts/github/<name>.sh` when the workflow checks out the
repo into `_helpers/`).

Extract the pre-existing literal-block offenders so the new lint
ships green:

  Ansible (script: module, file under <role>/files/)
    web-app-friendica   sync_addon.sh
    web-app-fider       create_admin_user.sh
    web-app-fider       configure_oidc_provider.sh
    web-app-mediawiki   install_or_update.sh
    web-app-mediawiki   composer_install_extension.sh
    web-app-xwiki       debug_superadmin.sh

  GitHub Actions (scripts/github/)
    pick_distro.sh
    guard_release.sh
    resolve_release_inputs.sh
    disk_pressure_report.sh

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:42:44 +02:00
kevinveenbirkenbachandClaude Opus 4.7 fe18ae43cf Fix enlarge_swap.sh starving deploys of disk space (#162)
Swap size was free(/)-25, which took ~99 GB on the 145 GB root fs.
Remaining ~25 GB then ran out mid-deploy during Playwright image
pulls (ENOSPC). Replace with a fixed 16 GB cap and use mountpoint
to detect a real /mnt partition instead of [ -d /mnt ], which
matched the empty placeholder dir on single-partition runners.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 16:54:03 +02:00
kevinveenbirkenbachandClaude Opus 4.7 033b045cf0 Add nested-container diagnostics to runner-state dump
Surfaces df, failed units, and hlth-disc-space status/journal from
inside the infinito container so failure-time dumps reflect the same
filesystem view that the disk-space health check evaluates, not just
the host.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:44:37 +02:00
kevinveenbirkenbachandClaude Opus 4.7 6fac8996ff Add runner-state diagnostic helper for CI deploy debugging
Extracts disk/memory/docker/swap dump into a reusable helper,
calls it pre/post swap resize, and runs it on deploy failure
across all four deploy workflows. Also adds SKIP_SWAP=1
short-circuit for A/B probing swap-related regressions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:37:54 +02:00
kevinveenbirkenbachandClaude Opus 4.7 0cfe0b4d51 Normalize whitespace in enlarge_swap.sh
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 03:23:37 +02:00
kevinveenbirkenbachandClaude Opus 4.7 8cdfcad9ef Enlarge CI runner swap dynamically across deploy workflows
Introduce scripts/github/enlarge_swap.sh that consumes all remaining
space on / minus a 25 GB buffer (Docker layers, checkout, runtime
state), falling back to /mnt when / is too small. Replaces the
default ~4 GB runner swap so transient memory spikes (e.g. peertube
plugin install, issue #162) don't trip the host OOM-killer on the
16 GB GitHub-hosted runner.

Wire the script into all four deploy test workflows (local, universal,
server, workstation) and flip free-disk-space to the aggressive config
(tool-cache, large-packages, docker-images, swap-storage all true):
the deploy actually runs inside the infinito container, so host-side
toolchains, language runtimes, and the default Docker layer cache are
dead weight. Update the workflow SPOT doc accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 03:18:45 +02:00
Environment Test da155e48e8 refactor(ci): extract app-discovery output logic into script
Inline shell duplicated across four deploy workflows. Single
source now in scripts/github/output_apps.sh.
2026-04-13 13:22:20 +02:00
Environment TestandClaude Sonnet 4.6 6835057707 fix(github): use owner:branch format for --head in gh pr create
When --repo is passed to gh, the --head argument must include the owner
in owner:branch format so GitHub can resolve the head SHA correctly.
Without it the GraphQL API returns 'Head sha can't be blank'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 19:22:05 +02:00
Environment TestandClaude Sonnet 4.6 46f8f775c1 fix(github): use --force instead of --force-with-lease for update branch push
--force-with-lease requires a remote-tracking ref to exist locally. In a
fresh CI checkout the update branch has no tracking ref, so the push is
rejected as stale. The update branch is always owned by automation, so
--force is safe here.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 19:20:22 +02:00
Environment TestandClaude Sonnet 4.6 86aa1a9629 fix(github): pass --repo explicitly to gh pr commands in open_update_pr.sh
Without --repo, gh targets the wrong repository context when GH_TOKEN is
used in a workflow that runs outside the target repo. Infer the repo from
the git remote URL and pass it to gh pr list, gh pr edit, and gh pr create.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 19:10:30 +02:00
Environment TestandClaude Sonnet 4.6 bf8c535988 feat(update): add docker image version updater CLI, workflow, and lint tests
- Add utils/docker/version_updater.py with CLI for updating Docker image versions
- Add cli/fix/docker_image_versions module wrapping the updater
- Add .github/workflows/update.yml replacing update-skills.yml
- Add scripts/github/ helpers: check_git_changes, install_update_python, open_update_pr, update_docker_image_versions
- Add tests/lint/filesystem/ for scripts/ and utils/ folder file-type enforcement
- Add tests/lint/ansible/ for legacy module usage and vars usage checks
- Reorganize tests/lint/repository/ and move test_vars_usage_in_yaml.py to ansible/
- Add artefact docs: files/github/workflow.md, scripst.md, utils.md
- Apply documentation.md standards to all modified markdown files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 18:38:39 +02:00
Environment TestandClaude Sonnet 4.6 5c1a963d30 docs(tools): restructure security and framework docs, add cleanup workflow
- Move flow/security/ghcr.md to tools/ghcr/authentication.md
- Move flow/security/mirror-cleanup.md to tools/ghcr/cleanup.md
- Move flow/security/branch.md to tools/github/branch.md
- Move flow/security/repository.md to tools/github/repository.md
- Move code/frameworks/ansible.md to tools/ansible.md
- Merge code/frameworks/Makefile.md into tools/make.md and extract file rules to artefact/files/makefile.md
- Rename tools/makefile.md to tools/make.md
- Add .github/workflows/images-mirror-cleanup.yml for manual GHCR cleanup
- Apply documentation.md standards: emojis on headlines, no em dashes, filename link text
- Fix all cross-references broken by directory restructuring

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 16:31:22 +02:00
kevinveenbirkenbach 0200b22298 Normalize scripts layout and Make targets 2026-03-28 09:00:38 +01:00