Two defects of the same kind: the repo asserted things about itself that were
not true, and nothing in it could tell.
A. CHANGELOG.md claimed CSP/HSTS/X-Frame-Options since 2026-08. `main`
contained none of it -- a repo-wide grep for
`content-security-policy|strict-transport-security|x-frame-options` matched
exactly one file, CHANGELOG.md itself. The only header on 0pt.app was
Vercel's own HSTS default, which does not survive the move to
Coolify/Traefik that siax.config.json and .gitea/workflows/cd.yml are
already pointed at.
- next.config.mjs: `headers()` on `/(.*)` with CSP (frame-ancestors 'none',
base-uri 'self', object-src 'none', form-action 'self'), HSTS,
X-Frame-Options DENY, X-Content-Type-Options, Referrer-Policy,
Permissions-Policy; plus poweredByHeader: false. Same idiom as
sax3l/siax-io's next.config.mjs.
- Carve-outs re-derived against THIS tree, not inherited: the stale
`ci/security-headers-and-scanning` branch (8d2ff73, 142 commits behind)
carried a `form-action https://checkout.stripe.com` allowance justified
by a redirect that is actually `window.location.href`, which form-action
does not govern -- dropped rather than kept as decorative permission.
frame-src is derived from NOCODB_BASE_URL/METABASE_SITE_URL, the same env
the components/embed.tsx iframe is configured from, so wiring that
component up cannot be silently blanked by this header (the failure
sax3l/siax-io recorded as SIO-013). 'unsafe-eval' is dev-only.
- tests/security/security-headers.test.ts: blocking regression gate inside
`pnpm run test`, i.e. the required "CI (SIAX Cloud) / quality" context.
Asserts against expectations written out in the test, not imported from
the config. Proven to fail: removing X-Frame-Options -> `pnpm run test`
exits 1; weakening frame-ancestors to 'self' -> exits 1.
B. scripts/siax-doctor.mjs validated that siax.repo.json fields were PRESENT,
never what they said. Measured on this tree: operationalState "running"
(false) and "down" (true) both gave 40/40, exit 0, byte-identical output.
- Value checks (enums, git.siax.io const, fleet node pattern, bare-hostname
form), cross-file consistency (declared prod hostnames must appear in
this repo's own siax.config.json / contracts/openapi.yaml, and vice
versa), and GOV-06 substantiation: operationalState must be backed by a
dated probe record in evidence/operational-state.json that agrees with
it. Liveness is not knowable offline; whether a liveness CLAIM is backed
is. Offline, deterministic, no network -- CI can never go red for want of
an internet connection.
- `--live` (opt-in) probes the declared hosts for real and checks the
headers on the wire; `--write-evidence` refreshes the record. Not wired
into CI on purpose.
- tests/repo/siax-doctor.test.ts runs the doctor inside `pnpm run test` and
asserts the negative cases against fixture trees (SIAX_DOCTOR_ROOT), so
the "cannot fail" defect cannot come back.
C. CHANGELOG.md is now true. The header claim stands; the four claims it was
bundled with (Trivy --exit-code 1, gitleaks, SHA-pinned actions, SBOM +
license artifacts) are still false on main and are listed as not
implemented instead of left asserted. All four live in .gitea/workflows/**,
a protected path on this repo, so they need an authorised workflow change.
Nothing under .gitea/workflows/** or .gitignore is touched.
Verified: pnpm run typecheck exit 0; pnpm run test exit 0 (74 files / 965
tests passed, up from 72/945); pnpm run build exit 0 and the built
.next/routes-manifest.json carries all six headers; node scripts/siax-doctor.mjs
55/55 exit 0; --live 57/57 exit 0. eslint on the new files exit 0 (repo lint is
advisory and its 17 pre-existing problems are unchanged).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7.2 KiB
Changelog
BACKLOG P1-3. Format loosely follows Keep a Changelog. No git tags/releases exist yet for this repo — this file starts the practice retroactively from real
git loghistory rather than inventing version numbers that were never cut. Dates are commit dates onmain, not calendar "release" dates (there have been none).
Unreleased
-
feat(deploy): appen är nu faktiskt byggbar och körbar utanför Vercel.next.config.mjssätteroutput: "standalone"; Dockerfilen är omskriven till samma form somsax3l/siax-io(som redan körs självhostat på flottan): fyra steg,node:22-alpine(matchar CI:s nodversion, var 24),libc6-compat, icke-root, HEALTHCHECK mot/api/health, npm/npx borttaget ur runtime-imagen. Uppmätt: image 1,33 GB -> 423 MB.--ignore-workspaceborttaget (dess motivering var inaktuell sedan P1-21) så containerinstallationen är samma kommando som CI kör;--prod=falsetillagt eftersom Coolify sätter NODE_ENV=production vid byggtid och pnpm då hoppar över devDependencies. -
fix(images):images.unoptimized: trueborttaget — det var v0-generatorns standardvärde, inte ett val (next.config.mjsvar orörd sedan initial commit). Självhostad bildoptimering kräver attsharpfaktiskt finns i runtime-imagen:next buildspårar den inte in i.next/standalone, ochoutputFileTracingIncludesfår Turbopack att panika på pnpms symlänkar. Sharp levereras därför i ett eget npm-steg i Dockerfile, pinnat till versionen ipnpm-lock.yaml. Verifierat i containern:/_next/imagesvarar 200 medimage/avif(1,46 MB PNG -> 6,7 kB). -
fix(security): response security headers are set by the app itself, in
next.config.mjsheaders()— CSP (incl.frame-ancestors 'none',base-uri 'self',object-src 'none',form-action 'self'), HSTS, X-Frame-OptionsDENY, X-Content-Type-Options, Referrer-Policy, Permissions-Policy — pluspoweredByHeader: false. Regression-gated bytests/security/security-headers.test.ts(blocking, runs inpnpm run test) and re-checkable against a live origin withnode scripts/siax-doctor.mjs --live. (BACKLOG P0-13, P1-15)Correcting this file: from 2026-08 until 2026-09-07 this bullet also claimed the headers themselves, while
maincontained none — a repo-wide grep forcontent-security-policy|strict-transport-security| x-frame-optionsmatched only CHANGELOG.md. The only thing setting HSTS on 0pt.app was Vercel's platform default (still observable on the 402 responses recorded inevidence/operational-state.json), which is not this repo's and does not survive the move to Coolify/Traefik. The claim is true as of this entry; the four claims it was bundled with are not, and are tracked in the section below. -
fix(repo-honesty):
scripts/siax-doctor.mjsvalidated thatsiax.repo.jsonfields were PRESENT, never what they said — measured:operationalState: "running"(false at the time; every declared host answered 402/404) and"down"(true) both produced 40/40 and byte-identical output. It now validates values (enums, hostname form), cross-file consistency (declared prod hostnames must appear in this repo's own deploy/contract config, and vice versa), and requiresoperationalStateto be backed by a dated probe record inevidence/operational-state.jsonthat agrees with it. Offline and deterministic by default;--live(opt-in) probes the real hosts. Gated bytests/repo/siax-doctor.test.ts, which also asserts the negative cases against fixture trees. (BACKLOG P1-19, control AGENT-04, GOV-06) -
fix(health):
/api/healthreports real per-dependency status instead of a hardcodedok: true; new/api/readyreadiness endpoint. (BACKLOG P0-3) -
docs/chore: repo-hygiene pass — schema-valid
siax.repo.json/siax.config.json(standard v2.0), ADRs, this CHANGELOG,siax:doctorscript, devcontainer,docs/architecture/ARCHITECTURE.md§5 "Ytor och paritet", CODEOWNERS, stale-link cleanup. (BACKLOG P1-1, P1-2, P1-3, P1-19, P1-20, P1-21, P2-5, P3-5)
Claimed here before 2026-09-07 but NOT implemented — status 2026-09-15
These were asserted by the earlier fix(security) bullet and were not true on
main at that time. Current state (measured against main, 2026-09-15):
- CI security gates now ENFORCE:
security.ymlandnightly.ymlrun Trivy with--exit-code 1(landed viaci/make-required-security-gate-real, 2026-09-08). (BACKLOG P0-16 — CLOSED) - gitleaks is still not run anywhere in this repo. (BACKLOG P0-19 — OPEN)
- Actions are still NOT pinned to commit SHAs (
actions/checkout@v4etc.). (BACKLOG P1-14 — OPEN) - No SBOM and no license inventory are produced or uploaded as CI artifacts.
(OPEN; the
fix/wire-signed-digest-to-deploybranch carries a prepared release chain that needs its cosign/registry secrets before it can land.)
2026-08-11 — Evasion-stack decision provenance
- Attributed and dated the account-owner's keep-decision on
services/scrapers/*acrossSECURITY.md,CONTRIBUTING.md,prompts/002-compliance-audit.md,renovate.json,.gitea/workflows/security.yml,docs/slo.md.
2026-08-09/10 — Golden Standard compliance pass (FAS 0–10)
docs/compliance/{INVENTORY,RELATIONS,OSS-INVENTORY,GOLDEN-STANDARD-REPORT,BACKLOG,SLUTRAPPORT}.mdwritten;siax.repo.jsonclassification recorded.fix(security):GET /api/ordersandGET /api/admin/metricsnow require auth (were live 200 anonymous — the routes sit outsidemiddleware.ts's/api/0pt/:path*matcher).fix(deploy):siax.config.jsondeploy.targetflipped fromverceltocoolify(config-only; the live instance is still on Vercel until a Coolify app is provisioned and DNS is cut over).feat(contract): OpenAPI 3.1 SSOT added (contracts/openapi.yaml);@vercel/analyticsandnext/font/googleremoved in favor of self-hosted@fontsource-variable/*(AR-4).ci(workflows): CD/security/nightly split under.gitea/workflows/.- README/SECURITY/CONTRIBUTING/AGENTS + runbooks (deploy, incident, backup-restore, oncall) + SLO doc added.
2026-08 — Auth + capability hardening ("Wave 2/3")
fix(auth):AUTH_ENFORCEdefault flipped to fail-closed on/api/0pt/*.- Zitadel Bearer-token verification wired into
middleware.ts(src/auth/zitadel.ts,src/auth/context.ts). - P0 capability layer built out:
0pt.query_source, document capture/extraction, Iceberg write-boundary, external writeback, dataset quality flow docs. - CI quality gate added (typecheck/lint/test),
.env.examplecommitted (previously blocked by a blanket.gitignore.env*rule).
2026-07-13 — Scraper stack (kept, see BACKLOG P3-3 / SECURITY.md)
services/scrapers/*(WAF-bypass, proxy rotation, ClickHouse pipeline) was added on the Gitea line of history. This is the subject of the dated, attributed account-owner decision referenced throughout this repo's compliance docs — not reopened or altered by this changelog entry.
Earlier
- Initial Next.js scaffold, order/catalog/portal UI, FastAPI engine
scaffold, i18n (EN/SV) and accessibility passes, lakehouse write-path
ownership ADR (
ADR-0030, in then0drepo).