p24-audit-log — Operations Reference

Repo: radieu/p24-audit-log (private) — created 2026-08-06 (see Provisioning status) Origin issue: #2652 — DSA Phase 1A Plan: #2637 Scaffolding tracked by: #3471


Purpose

p24-audit-log is the append-only audit-log repository for the DSA (Digital Services Act) compliance workstream. Autonomous workers and humans append short, structured notes recording deployment decisions, workarounds, and open items so there is a durable, PR-reviewed audit trail outside any single service repo.

Downstream work (issues C #2655 and D #2656) writes to this repo. As of 2026-08-06 this no longer needs a static AUDIT_LOG_WRITE_TOKEN PAT — see Write credential — GitHub App, not a static PAT.


Note schema

Every entry is prefixed with exactly one tag:

TagMeaning
[DEPLOYED]A change that reached production, with what/when/where
[DECISION]An architectural or process decision and its rationale
[WORKAROUND]A temporary measure in place until a proper fix lands
[OPEN ITEM]A known gap or follow-up not yet resolved

Provisioning status

Done, 2026-08-06 — resolved in a Class A secret-manager session on the developer workstation (has a human radieu OAuth gh login with repo+workflow scope, which the bms-4/#3471 worker never had access to — its blocker analysis below is preserved for context, not because it recurred).

StepStatus
1. Create private repo radieu/p24-audit-log✅ done
2. README.md + .github/workflows/auto-merge.yml as initial commit on main✅ done
3. Branch protection on main (require PR, dismiss stale reviews)✅ done
4. Repo Settings → enable Allow auto-merge✅ done
5. Write credential for issues C/D✅ done — not a new PAT, see next section

Why the earlier blocker doesn’t apply here (historical context, #3471)

The bms-4 infra-task worker could not create the repo — no token reachable from that host has Administration: write on the radieu user account:

CredentialResult
Active worker token (radieu, fine-grained PAT)Resource not accessible by personal access token
AI-Dev-BMS4-1 (classic repo scope)cannot create a repository for radieu (different user namespace)
N8N_BMS4_GH_TOKEN (SOPS, fine-grained PAT)Resource not accessible by personal access token

That blocker is specific to the bms-4 worker’s credentials, not to the GitHub platform. A Class A p24-infra session’s own gh auth login (human radieu account, classic OAuth token, repo scope) has Administration: write on its own user namespace by default, so gh repo create radieu/... works from there without any new credential. Commands actually run (steps 1–4):

gh repo create radieu/p24-audit-log --private \
  --description "DSA audit log — deployment decisions, workarounds, open items"
# README.md + .github/workflows/auto-merge.yml pushed as the first two commits on main via
# the Contents API (PUT repos/radieu/p24-audit-log/contents/<path>) — no local clone needed.
gh api --method PUT repos/radieu/p24-audit-log/branches/main/protection \
  --input branch-protection.json   # required_pull_request_reviews.dismiss_stale_reviews=true
gh repo edit radieu/p24-audit-log --enable-auto-merge

Paste-ready artifacts

README.md

# p24-audit-log
 
Append-only DSA compliance audit log. One note per commit/PR.
 
## Note schema
 
Prefix every entry with exactly one tag:
 
- `[DEPLOYED]`  — a change that reached production (what / when / where)
- `[DECISION]`  — an architectural or process decision and its rationale
- `[WORKAROUND]`— a temporary measure until a proper fix lands
- `[OPEN ITEM]` — a known gap or follow-up not yet resolved
 
## Workflow
 
- Every change lands via PR (branch protection enforced).
- Label a PR `auto-merge` to have it squash-merged automatically once checks pass.

.github/workflows/auto-merge.yml

name: auto-merge
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  auto-merge:
    runs-on: ubuntu-latest
    if: contains(github.event.pull_request.labels.*.name, 'auto-merge')
    steps:
      - run: gh pr merge --auto --squash "${{ github.event.pull_request.number }}"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Write credential — GitHub App, not a static PAT

The original plan (#2652, #3471) called for a fine-grained PAT named AUDIT_LOG_WRITE_TOKEN (contents:write, scoped to this repo only), stored as a static value in secrets/n8n-bms4.env.sops. GitHub has no API to self-issue a new PAT — creation is UI-only, 2FA-gated — so that step would have stayed a permanent human/Tier-3 dependency.

That step is no longer needed. This repo is already covered by the same GitHub App the ecosystem uses elsewhere to eliminate PAT consumers (App 2109526, installation 142989418, installed with all-repositories access on the radieu account — see docs/playbooks/n8n/github-app-token-n8n.md). A newly created repo under radieu/* is automatically in scope for an all-repos installation — no per-repo “add repository” step was needed. The App’s contents: write permission is already confirmed granted at the installation (audited in docs/plans/plan-4245-gh-app-token-fleet-migration.md §3). Its credentials already live in secrets/n8n-bms4.env.sops (GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY_B64, GITHUB_APP_INSTALLATION_ID) and are already deployed to bms-4 — no new SOPS entry was added for this issue.

Any consumer that needs to write to radieu/p24-audit-log (git push, or a REST/Contents-API call) mints a fresh, narrowly-scoped, 1-hour installation token on demand instead of reading a static secret:

AUDIT_LOG_WRITE_TOKEN=$(python3 /opt/p24-infra/scripts/gh-app-token --repos p24-audit-log --permissions contents:write)
git remote set-url origin "https://x-access-token:${AUDIT_LOG_WRITE_TOKEN}@github.com/radieu/p24-audit-log.git"
unset AUDIT_LOG_WRITE_TOKEN

scripts/gh-app-token (built for #4068) reads the App credentials from whichever of /opt/p24-infra/bms-4/.env or /opt/p24-infra/monitoring/.env carries them, so this works unchanged on bms-4 or vps-i1. A --repos/--permissions-scoped call is never cached and is strictly narrower than the originally-proposed PAT (1h TTL vs 90 days, single-repo, no browser/2FA ever required to mint or rotate it).

Action for whoever (re-)implements scripts/dsa/run-audit.sh (issue #2656 — the draft implementation in PR #2661 was closed unmerged): use the snippet above instead of AUDIT_LOG_WRITE_TOKEN=$(grep -m1 '^AUDIT_LOG_WRITE_TOKEN=' "$ENV_FILE" | cut -d= -f2-). The downstream git remote set-url line does not need to change — an App installation token is a drop-in replacement for a PAT in the x-access-token:<token>@github.com git-credential form.

Never hardcode any token; both the App private key and any minted installation token are handled only as env vars, never written to a committed file. See secret-manager.md.


Compliance

  • Outstanding: register p24-audit-log in Supabase dev_r_services (compliance_workbook='yes', workbook_url pointing at this doc) — the repo now exists so this can proceed; not done as part of this issue (secret-manager role scope; hand off per docs/playbooks/dev-r-services-insert.md).
  • This ops doc satisfies the “ops doc in docs/” requirement for the new repo.