Commit Graph
268 Commits
Author SHA1 Message Date
Simon AxelssonandClaude Opus 5 8ebc90ffa3 fix(security,repo-honesty): real security headers + a doctor that checks truth, not presence
masterplan-lock / check (pull_request) Successful in 4s
masterplan-lock / check (push) Successful in 7s
CI (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / security (push) Successful in 18s
CI (SIAX Cloud) / quality (push) Successful in 39s
CI (SIAX Cloud) / integration (pull_request) Successful in 41s
CI (SIAX Cloud) / integration (push) Successful in 44s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 1m37s
Security Scan (SIAX Cloud) / security (push) Successful in 1m35s
CI (SIAX Cloud) / quality (pull_request) Successful in 3m4s
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>
2026-09-15 02:43:32 +02:00
adminandClaude Sonnet 5 d41f30535b fix(test): replay full migration chain in source-registry realinfra test
tests/p0/source-registry-postgres.realinfra.test.ts only applied
sql/002_source_registry.sql before running assertions. sql/007_ingestion_plane.sql
later added opt_sources.owner_id, and src/repositories/postgres-source-repository.ts's
INSERT has named that column ever since -- but nothing caught the drift because
SOURCE_REGISTRY_TEST_DATABASE_URL is never set in CI (.gitea/workflows/ci.yml has no
job that sets it), so this suite has silently skipped in every CI run.

Verified against a real disposable Postgres 16 container: before this fix, all 7
tests failed with `column "owner_id" of relation "opt_sources" does not exist`;
after replaying every sql/*.sql file in order (same pattern already used by
tests/analytics/analytics-domain-postgres.realinfra.test.ts), all 7 pass.

Found while auditing 0pt's Analytics/BI layer (MetricFlow/Cube/ClickHouse/
Trino/DuckDB) and standing up real Postgres/ClickHouse containers to verify
those claims for real; this bug is adjacent (source registry, not analytics)
but was directly encountered and is a small, safe, test-only fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 02:40:52 +02:00
admin 17bd1b40a0 feat(0pt): record legitimate-interest stance — B2B contacts, company-linked only
Recorded decision (Simon 2026-08-31): personal data may be stored under
legitimate interest ONLY as business contacts bound to a company/org entity.
Gate enforces it: legitimate_interest requires purpose=business_contact and
entity_linked_only=true; recordStored() requires entity_id (orgnr/rgs/LEI,
hashed) and refuses person-only rows. +1 test; suite 167 pass | 1 skip;
typecheck clean.
2026-09-15 02:40:52 +02:00
admin 12080fc517 feat(0pt): PII-Gate GDPR-guardrail for personal-data sources (fail-closed)
PiiGateService makes any future personal-data source (ratsit.se and other
directory domains) technically GDPR-OK before the first byte is stored:
- recorded legal basis (art. 6) with basis_ref evidence, no policy => fail-closed
- data minimisation via field allowlist (art. 5(1)(c))
- storage limitation + enforceRetention purge (art. 5(1)(e))
- sha256-only identity keys + log redaction (art. 25/32)
- accessStatement / erase subject-rights surfaces (art. 15/17)
- robots/rate confirmation required for web+api sources; no stealth/bypass
- audit trail via AUD0 at risk L3 (0pt.pii_*)
- gate enabled by default in SourceQueryService

10 new tests; full suite 166 pass | 1 skip; typecheck (blocking gate) clean.
2026-09-15 02:40:52 +02:00
admin 9cf797b5c8 Merge pull request 'feat(toolchain): 0pt-pilot — mise task-kontrakt (node/pnpm pinat) + lefthook + template-pin + dokumentation (W3, pilot 2/3)' (#55) from feat/selected-toolchain-pilot into main
Deploy to Coolify / deploy (push) Successful in 2s
masterplan-lock / check (push) Successful in 8s
CI (SIAX Cloud) / security (push) Successful in 14s
Security Scan (SIAX Cloud) / security (push) Successful in 28s
CI (SIAX Cloud) / quality (push) Successful in 34s
CI (SIAX Cloud) / integration (push) Successful in 41s
2026-09-14 21:03:46 +00:00
admin 61b593b4c0 fix(toolchain): check = typecheck (lint ar CI-advisory: legacy-noise) — lint som separat task, dokumenterat
masterplan-lock / check (push) Successful in 4s
masterplan-lock / check (pull_request) Successful in 4s
CI (SIAX Cloud) / security (pull_request) Successful in 14s
CI (SIAX Cloud) / quality (push) Successful in 32s
CI (SIAX Cloud) / integration (pull_request) Successful in 26s
CI (SIAX Cloud) / quality (pull_request) Successful in 35s
CI (SIAX Cloud) / security (push) Successful in 45s
Security Scan (SIAX Cloud) / security (push) Successful in 45s
CI (SIAX Cloud) / integration (push) Failing after 45s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 1m13s
2026-09-14 23:01:15 +02:00
admin 45b2d65d42 feat(toolchain): 0pt-pilot — mise task-kontrakt (node 22.13.0/pnpm 9.15.9) + lefthook + template-pin + README/AGENTS (W3, pilot 2/3)
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / security (push) Successful in 14s
Security Scan (SIAX Cloud) / security (push) Successful in 23s
CI (SIAX Cloud) / integration (push) Successful in 25s
CI (SIAX Cloud) / quality (push) Successful in 34s
2026-09-14 22:59:02 +02:00
admin c0457343b8 Merge pull request 'fix(security): add SSRF guard to Fabric/OneLake adapter's sqlEndpoint' (#54) from fix/fabric-onelake-ssrf-guard into main
Deploy to Coolify / deploy (push) Successful in 2s
masterplan-lock / check (push) Successful in 3s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / quality (push) Successful in 36s
CI (SIAX Cloud) / integration (push) Successful in 47s
2026-09-13 15:39:20 +00:00
adminandClaude Sonnet 5 4caf122129 fix(security): add SSRF guard to Fabric/OneLake adapter's sqlEndpoint
masterplan-lock / check (push) Successful in 7s
CI (SIAX Cloud) / security (push) Successful in 19s
Security Scan (SIAX Cloud) / security (push) Successful in 27s
CI (SIAX Cloud) / quality (push) Successful in 33s
CI (SIAX Cloud) / integration (push) Successful in 46s
masterplan-lock / check (pull_request) Successful in 4s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m11s
CI (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / quality (pull_request) Successful in 35s
connection_config.sqlEndpoint on POST /api/0pt/sources/{sourceId}/query
was passed straight from the request body to the mssql TDS driver as the
outbound connection target, with only its http(s):// scheme stripped —
no hostname allowlist or private/loopback/link-local/cloud-metadata
guard. This route already requires a Zitadel bearer token + tenant match
(P014 tenant guard), so this was not anonymously exploitable, but it is
the exact SSRF shape found and exploited-in-principle elsewhere in this
estate tonight (press0), so it's worth closing as defense-in-depth.

Adds src/lib/security/ssrf-guard.ts: resolves the endpoint's hostname
and rejects any address in a private/loopback/link-local/cloud-metadata/
unspecified range (RFC1918, 127.0.0.0/8, 169.254.0.0/16 incl. the
169.254.169.254 metadata address, ::1, fc00::/7, fe80::/10, IPv4-mapped
IPv6), failing closed on DNS resolution errors. The range-check logic is
ported 1:1 from press0's src/lib/security/ssrf-guard.ts built the same
night for the same bug class against a fetch()-based URL there; this
module's surface differs because sqlEndpoint is a bare host[:port], not
a fetchable URL. The DNS lookup is injectable (mirrors this adapter's
existing fetchImpl pattern) so tests are hermetic.

FabricOneLakeAdapter.getPool() now calls the guard before loadDriver()/
getToken()/opening the TDS pool, so a blocked target never reaches a
real outbound connection attempt or spends an AAD token exchange.

Tests: new tests/p0/fabric-onelake-ssrf-guard.test.ts unit-tests the
guard module directly (range boundaries, IPv4-mapped-IPv6 bypass
attempt, fail-closed on DNS failure/empty answer). New adapter-level
tests in tests/p0/fabric-onelake-adapter.test.ts prove (a) a
private-IP-resolving sqlEndpoint is rejected before fetch/connect is
ever called, (b) a literal loopback sqlEndpoint is rejected the same
way, and (c) a normal external Fabric hostname still passes the guard
and completes the query — the guard doesn't false-block legitimate
targets. Existing adapter tests are updated to inject a deterministic
DNS resolver so they stay hermetic instead of depending on real DNS.

Full suite: 997 passed, 0 failed, 184 skipped (self-skipping realinfra
tests with no live backend this run). typecheck and lint clean on all
touched files.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 02:18:23 +02:00
admin 4a4ec6a575 Merge pull request 'fix(prod): close legacy storage fallbacks in orders/subscriptions/blobs' (#51) from fix/production-storage-fallbacks into main
Deploy to Coolify / deploy (push) Failing after 2s
masterplan-lock / check (push) Successful in 6s
CI (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / integration (push) Successful in 25s
Security Scan (SIAX Cloud) / security (push) Successful in 30s
CI (SIAX Cloud) / quality (push) Successful in 37s
2026-09-10 22:59:06 +00:00
admin 317ba71cd0 Merge pull request 'chore(conformance): masterplan-lock guard + PLAN index' (#52) from conformance-masterplan-lock into main
CI (SIAX Cloud) / quality (push) Successful in 36s
Deploy to Coolify / deploy (push) Failing after 2s
masterplan-lock / check (push) Successful in 8s
Security Scan (SIAX Cloud) / security (push) Successful in 21s
CI (SIAX Cloud) / security (push) Successful in 28s
CI (SIAX Cloud) / integration (push) Successful in 47s
2026-09-10 18:01:30 +00:00
siax-bot bb4cc78145 chore(conformance): add masterplan-lock guard + PLAN/MASTERPLAN_INDEX.md
masterplan-lock / check (pull_request) Successful in 5s
masterplan-lock / check (push) Successful in 6s
CI (SIAX Cloud) / security (pull_request) Successful in 13s
CI (SIAX Cloud) / security (push) Successful in 17s
Security Scan (SIAX Cloud) / security (push) Successful in 13s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 13s
CI (SIAX Cloud) / quality (push) Successful in 35s
CI (SIAX Cloud) / integration (push) Successful in 41s
CI (SIAX Cloud) / quality (pull_request) Successful in 46s
CI (SIAX Cloud) / integration (pull_request) Successful in 48s
Per siax-standard conformance sweep: repo lacked the masterplan-lock CI guard
(.gitea/workflows/masterplan-lock.yml + scripts/check-masterplan-lock.sh) and a
repo-local PLAN/MASTERPLAN_INDEX.md. Copied from sax3l/st0re template (generic
POSIX sh check), stub PLAN index with locked architecture principles and
pointer to sax3l/siax-masterplan.

Refs: sax3l/siax-standard (conformance sweep 2026-09-10)
2026-09-10 18:17:07 +02:00
adminandClaude Opus 5 db868f4bdf fix(prod): close legacy storage fallbacks in orders/subscriptions/blobs
CI (SIAX Cloud) / security (push) Successful in 14s
Security Scan (SIAX Cloud) / security (push) Successful in 21s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / quality (push) Successful in 44s
CI (SIAX Cloud) / integration (push) Successful in 45s
CI (SIAX Cloud) / integration (pull_request) Successful in 27s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m45s
The `resolveStoreMode` kill switch (Master-DoD §3/§10) covered the newer
`src/repositories/*` stores but not two older paths, both of which are
live production execution paths today.

1. LEGACY NEXT.JS STORES. `lib/orders-store.ts` and
   `lib/subscriptions-store.ts` predate `src/platform/dependency-mode.ts`
   and called `getSql()` directly, silently falling back to module-global
   `Map`s when no database is configured. For orders, payments and
   subscriptions that is not a degraded mode, it is invisible loss of
   money-bearing state: the API returns 201 and the row evaporates on the
   next restart or on any other replica. The live 0pt deployment
   (Coolify app 54) runs NODE_ENV=production with DATABASE_URL,
   POSTGRES_URL and POSTGRES_PRISMA_URL all unset — so this is the
   behavior in production right now, across 7 API routes.

   These now go through `getSqlForDurableStore()`, which reuses the SAME
   `resolveStoreMode` decision every `src/repositories/*` store already
   uses rather than re-implementing a second production check. The reuse
   is load-bearing: `isProductionRuntime` deliberately exempts
   `NEXT_PHASE=phase-production-build`, because `next build` runs
   page-data collection under NODE_ENV=production while serving nothing.
   A naive `process.env.NODE_ENV === "production"` test here would have
   failed the BUILD instead of protecting a request path.

2. LOCALBLOBSTORE. It writes document bytes to a container-local disk
   while `document-capture-service` registers an artifact pointer
   claiming the bytes are stored — durable object storage silently
   swapped for ephemeral disk. It is the default blob store for both the
   capture and extraction services. In production it now raises
   DEPENDENCY_UNAVAILABLE (capability blocked: no ST0RE bytes path
   exists yet) instead of fabricating success. Asserted per-operation,
   not in the constructor, so merely wiring the services is not fatal —
   only actually persisting or reading bytes is.

Evidence: full suite 956 passed / 184 skipped, typecheck clean,
dependency-cruiser 0 errors, lint identical to main's pre-existing
baseline (17 problems, none in changed files). Both guards asserted in
both directions and mutation-tested: bypassing resolveStoreMode -> 2
failed; dropping the write assert -> 2 failed; dropping the read assert
-> 1 failed; all restored -> 8 passed. 7 non-test call sites.

DEPLOYMENT NOTE: merging changes no runtime (no Gitea webhook exists on
any repo; deploys are manual). Deploying this build REQUIRES
provisioning DATABASE_URL for 0pt first, or the order/subscription
routes will correctly return DEPENDENCY_UNAVAILABLE instead of silently
accepting orders into memory. That provisioning is a Simon action.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 17:38:51 +02:00
admin d26a7045bd Merge pull request 'fix(contract): deklarera internal-er + quality bridge-run + internalToken-scheme' (#50) from fix/contract-declare-internal-er-quality into main
Deploy to Coolify / deploy (push) Failing after 2s
Security Scan (SIAX Cloud) / security (push) Successful in 13s
CI (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / quality (push) Successful in 35s
CI (SIAX Cloud) / integration (push) Successful in 1m16s
2026-09-08 23:31:25 +00:00
admin 8f47fd3ad3 fix(contract): deklarera internal-er + quality bridge-run med internalToken-scheme — parity-gatens E_PATH_NOT_DECLARED/E_AUTH_SCHEME_UNDECLARED
CI (SIAX Cloud) / security (push) Successful in 13s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 14s
CI (SIAX Cloud) / integration (pull_request) Successful in 33s
CI (SIAX Cloud) / quality (pull_request) Successful in 35s
CI (SIAX Cloud) / quality (push) Successful in 1m9s
CI (SIAX Cloud) / integration (push) Successful in 1m38s
services/api/workers/{resolve,quality_bridge}.py anropar båda rutterna med
X-Internal-Token sedan langt tillbaka; rutterna (app/api/0pt/internal/er/
candidates + app/api/0pt/quality/bridge-run) har alltid existerat men
kontraktet shipade dem aldrig. Wire ar sanning — kontraktet matchar nu:
- POST /api/0pt/internal/er/candidates (full request/response-schema ur
  src/er/request-validation.ts + entity-resolution-service.ts)
- POST /api/0pt/quality/bridge-run (flyttad fran ops-losen deklaration till
  internal-gruppen med internalToken-security)
- components.securitySchemes.internalToken (X-Internal-Token header,
  verifyInternalServiceToken)
2026-09-09 01:24:53 +02:00
admin fb97b87aea Merge pull request 'feat: Work entity resolution — review-gated ER (kanoniserad från GitHub #11)' (#48) from feat/work-entity-intelligence into main
Deploy to Coolify / deploy (push) Failing after 2s
Security Scan (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / security (push) Successful in 26s
CI (SIAX Cloud) / integration (push) Successful in 42s
CI (SIAX Cloud) / quality (push) Successful in 51s
2026-09-08 20:54:01 +00:00
admin 213294bc55 fix: use services/api pytest import convention
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 27s
CI (SIAX Cloud) / integration (push) Successful in 31s
CI (SIAX Cloud) / integration (pull_request) Successful in 32s
Security Scan (SIAX Cloud) / security (push) Successful in 43s
CI (SIAX Cloud) / security (pull_request) Successful in 43s
CI (SIAX Cloud) / quality (pull_request) Successful in 53s
CI (SIAX Cloud) / quality (push) Successful in 55s
2026-09-08 22:50:05 +02:00
admin 97373bae0d test: cover review-gated entity resolution 2026-09-08 22:50:05 +02:00
admin ae9a33edf2 feat: add review-gated entity resolution for Work ecosystem 2026-09-08 22:50:05 +02:00
admin 5abc842dfd docs: add ecosystem data acquisition and entity plan 2026-09-08 22:50:05 +02:00
admin 6b1723dbd0 Merge pull request 'chore(deps): update clickhouse/clickhouse-server docker tag to v24.12' (#27) from renovate/clickhouse-clickhouse-server-24.x into main
Deploy to Coolify / deploy (push) Failing after 2s
Security Scan (SIAX Cloud) / security (push) Successful in 13s
CI (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / quality (push) Successful in 33s
CI (SIAX Cloud) / integration (push) Successful in 44s
2026-09-08 20:49:01 +00:00
admin d2a42a449f Merge pull request 'fix(deps): update dependency next to v16.3.4' (#47) from renovate/web-stack into main
Deploy to Coolify / deploy (push) Failing after 1s
CI (SIAX Cloud) / security (push) Successful in 14s
Security Scan (SIAX Cloud) / security (push) Successful in 18s
CI (SIAX Cloud) / integration (push) Successful in 32s
CI (SIAX Cloud) / quality (push) Successful in 1m10s
2026-09-08 20:48:57 +00:00
admin 36df983b4f Merge pull request 'chore(deps): update react monorepo to v19.2.18' (#46) from renovate/react-monorepo into main
Deploy to Coolify / deploy (push) Failing after 1s
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / integration (push) Successful in 26s
CI (SIAX Cloud) / quality (push) Successful in 35s
2026-09-08 20:48:52 +00:00
admin 914fb8170c Merge pull request 'feat(deploy): gör 0pt körbar utanför Vercel — standalone + bevisad Coolify-image' (#40) from feat/coolify-standalone-deployable into main
Deploy to Coolify / deploy (push) Failing after 2s
CI (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / integration (push) Successful in 26s
CI (SIAX Cloud) / quality (push) Successful in 33s
Security Scan (SIAX Cloud) / security (push) Successful in 55s
2026-09-08 20:48:44 +00:00
admin 6233e09eac Merge pull request 'fix(ci): make the required security gate able to fail + repair the integration guard that could not pass' (#45) from ci/make-required-security-gate-real-20260908 into main
Deploy to Coolify / deploy (push) Failing after 4s
CI (SIAX Cloud) / security (push) Successful in 17s
Security Scan (SIAX Cloud) / security (push) Successful in 31s
CI (SIAX Cloud) / quality (push) Successful in 52s
CI (SIAX Cloud) / integration (push) Successful in 1m1s
2026-09-08 20:48:40 +00:00
admin b212a11870 Merge pull request 'chore: untrack committed __pycache__ and scraper output dumps (P4-4)' (#22) from chore/untrack-pycache-and-scraper-output into main
Deploy to Coolify / deploy (push) Failing after 1s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / quality (push) Successful in 37s
CI (SIAX Cloud) / integration (push) Failing after 47s
2026-09-08 20:48:36 +00:00
admin b4ec38940c Merge pull request 'feat(P-001, P-002): 0pt→N0D quality delegation + internal OpenAPI' (#49) from fix/p001-p002-quality-delegation into main
Deploy to Coolify / deploy (push) Failing after 2s
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / integration (push) Failing after 47s
CI (SIAX Cloud) / quality (push) Successful in 1m2s
2026-09-08 20:41:42 +00:00
admin 2d34cb1629 feat(P-001, P-002): 0pt→N0D quality delegation + internal OpenAPI
CI (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (push) Successful in 17s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / integration (push) Failing after 27s
CI (SIAX Cloud) / integration (pull_request) Failing after 31s
CI (SIAX Cloud) / quality (pull_request) Successful in 42s
CI (SIAX Cloud) / quality (push) Successful in 42s
2026-09-08 22:38:47 +02:00
Renovate e080cae785 fix(deps): update dependency next to v16.3.4
renovate/stability-days Updates have met minimum release age requirement
Security Scan (SIAX Cloud) / security (push) Successful in 17s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / integration (pull_request) Failing after 45s
CI (SIAX Cloud) / security (pull_request) Successful in 46s
CI (SIAX Cloud) / security (push) Successful in 45s
CI (SIAX Cloud) / integration (push) Failing after 46s
CI (SIAX Cloud) / quality (pull_request) Successful in 56s
CI (SIAX Cloud) / quality (push) Successful in 1m6s
2026-09-08 03:01:43 +00:00
Renovate e70f01ae7e chore(deps): update react monorepo to v19.2.18
renovate/stability-days Updates have met minimum release age requirement
Security Scan (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / security (push) Successful in 23s
Security Scan (SIAX Cloud) / security (push) Successful in 26s
CI (SIAX Cloud) / quality (push) Successful in 39s
CI (SIAX Cloud) / quality (pull_request) Successful in 45s
CI (SIAX Cloud) / integration (pull_request) Failing after 49s
CI (SIAX Cloud) / integration (push) Failing after 50s
CI (SIAX Cloud) / security (pull_request) Successful in 52s
2026-09-08 03:01:37 +00:00
Simon AxelssonandClaude Opus 5 be5e598646 fix(ci): replace the integration anti-skip guard that could not pass
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 18s
CI (SIAX Cloud) / integration (push) Successful in 29s
CI (SIAX Cloud) / quality (push) Successful in 47s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
CI (SIAX Cloud) / quality (pull_request) Successful in 38s
The guard grepped vitest's HUMAN output:

    grep -qE "skipped" && ! grep -qE "Tests  [0-9]+ passed"

vitest colours that summary. The real line emitted on these runners is

    ESC[2m      Tests ESC[22m ESC[1mESC[32m97 passedESC[39m | ...

so ANSI escapes sit between "Tests " and the digits and the
two-spaces-then-digits pattern can never match. The first grep still
matched "skipped", so the condition was true whenever a single test
skipped -- no matter how many passed.

Measured on run 13911 job 31183 (this branch, 2026-09-08): 13 files /
97 tests PASSED, 1 file / 2 tests skipped, and the step still printed
"FATAL: integration suites skipped instead of running" and exited 1.
That message was false; the suites ran.

It survived review because it is correct locally -- redirecting vitest
to a file disables its colour, so the pattern matches on a developer
machine and misfires only under CI.

Replaced with vitest's JSON reporter: structured, colourless, and
fail-closed if the report is missing. A/B measured on real reports in
BOTH directions, so the replacement is not merely green:

    all skipped      (0 passed / 99 pending)  -> exit 1  (protection kept)
    945 passed + 184 skipped                  -> exit 0  (false red gone)
    report file absent                        -> exit 1  (fail closed)

The anti-skip guarantee the original guard was written for is preserved:
a run where every suite skips still fails.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:23:55 +02:00
Simon AxelssonandClaude Opus 5 1322d26fac fix(ci): make the required security gate capable of failing
Security Scan (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / security (push) Successful in 25s
CI (SIAX Cloud) / integration (push) Failing after 31s
CI (SIAX Cloud) / quality (push) Successful in 34s
Branch protection on `main` requires exactly two status contexts:

    CI (SIAX Cloud) / security (push)
    CI (SIAX Cloud) / quality (push)

The `security` half could not fail. All three Trivy invocations in this
repo ran with `--exit-code 0`, so the scanner reported findings to stdout
and then exited 0 regardless.

Measured on main @4514d97, 2026-09-08, same scanner (Trivy 0.73.0), same
target, only the flag differing:

  A  --exit-code 0, clean tree                        -> exit 0
  B  --exit-code 0, planted AWS secret access key     -> exit 0  (DETECTED
     as CRITICAL in the report, gate still green)
  C  --exit-code 1, same planted secret               -> exit 1
  D  --exit-code 1, probe removed                     -> exit 0

B is the defect: the required context reported success while the scanner
had a CRITICAL secret in hand. D is why this is safe to land now -- the
tree is clean today, so flipping the flag does not open the gate red.
(PR #19 measured 19 HIGH findings on 2026-08-11; those dependencies have
since been updated on main, 142 commits later.)

The other required context, `quality`, was verified real and left alone:
a planted type error fails `pnpm run typecheck` (exit 2) and a planted
failing assertion fails `pnpm run test` (exit 1, 945 passed baseline).

nightly.yml carried the same flag. A nightly scan exists to catch CVEs
published against code that did not change; with `--exit-code 0` it could
never raise that alarm.

Not fixed here, needs an owner decision: services/scrapers/requirements.txt
uses `>=` ranges only. Trivy's pip scanner cannot resolve unpinned
specifiers, so it omits the file from the scan entirely -- it never appears
as a target. Pinning those same floors with `==` surfaces 3 HIGH findings
(aiohttp CVE-2025-69223, aiohttp CVE-2026-69244, lxml CVE-2026-41066).
Deliberately NOT suppressed with `--skip-dirs`, which would turn a
measurable blind spot into declared policy.

Job names are unchanged, so both required context strings are preserved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:16:08 +02:00
admin 4514d97e13 Merge pull request 'feat: durable AUD0 outbox + dataset/search/ER HTTP surfaces + P065 stängd (kod, utan workflow-ändringar)' (#43) from feat/aud0-outbox-code-20260907 into main
Security Scan (SIAX Cloud) / security (pull_request) Successful in 13s
CI (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / quality (pull_request) Successful in 49s
CI (SIAX Cloud) / integration (pull_request) Failing after 54s
Deploy to Coolify / deploy (push) Failing after 4s
CI (SIAX Cloud) / security (push) Successful in 13s
Security Scan (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / integration (push) Failing after 28s
CI (SIAX Cloud) / quality (push) Successful in 38s
2026-09-07 17:53:04 +00:00
admin 3c9abda020 ci: tar bort python-engine.yml — kräver estate-policy-beslut (skyddade filer)
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / security (pull_request) Successful in 21s
CI (SIAX Cloud) / integration (push) Failing after 27s
CI (SIAX Cloud) / quality (push) Successful in 35s
CI (SIAX Cloud) / integration (pull_request) Failing after 36s
CI (SIAX Cloud) / quality (pull_request) Successful in 50s
Ny blockerande pytest-gate + Postgres/OpenSearch/ClickHouse-härdningen i
ci.yml ur PR #10 berör .gitea/workflows/ (estate-skydd). De nya real-infra-
testerna är exekverade lokalt (Postgres 5/5; OpenSearch/CH-gate behåller
main:s konfig tills beslut) — hålls utanför merge så koden landar.
2026-09-07 19:52:02 +02:00
admin 6befaa7be7 test(er): resolv-determinism — match-pairs behöver hard-rule decided_by
CI (SIAX Cloud) / security (pull_request) Successful in 14s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / security (push) Successful in 29s
CI (SIAX Cloud) / integration (pull_request) Failing after 31s
CI (SIAX Cloud) / integration (push) Failing after 32s
CI (SIAX Cloud) / quality (pull_request) Successful in 36s
CI (SIAX Cloud) / quality (push) Successful in 38s
Python Engine CI (SIAX Cloud) / python-engine (push) Successful in 9m31s
Python Engine CI (SIAX Cloud) / python-engine (pull_request) Successful in 9m32s
_apply_matches ignorerar medvetet decided_by=score (defence in depth:
score/fuzzy får aldrig skapa canonical identity-länkar) — testernas
stub-bridge returnerade score-pairs och förväntade ändå merge → CI-fail var
implementationen som hade rätt. Pairs är nu decided_by=stable-identifiers.v3.

Verifierat: pytest services/api/tests 6+14 pass, full unit 945/945,
typecheck EXIT 0, real-Postgres 5/5.
2026-09-07 19:50:02 +02:00
Simon Axelsson cc6fbd71c5 Merge commit '3edc56d' into HEAD 2026-09-07 19:46:53 +02:00
admin 0eb9429932 ci: behåller main:s workflows (estate-skyddade filer)
CI (SIAX Cloud) / security (push) Successful in 15s
Security Scan (SIAX Cloud) / security (push) Successful in 14s
CI (SIAX Cloud) / quality (push) Failing after 27s
CI (SIAX Cloud) / integration (push) Failing after 30s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 14s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / quality (pull_request) Failing after 20s
CI (SIAX Cloud) / integration (pull_request) Failing after 35s
Python Engine CI (SIAX Cloud) / python-engine (push) Failing after 4m56s
Python Engine CI (SIAX Cloud) / python-engine (pull_request) Failing after 4m48s
CI-härdningen ur PR #10 (Trivy HIGH/CRITICAL blocking, Postgres-service i
integration, python-engine pytest-gate) berör .gitea/workflows/ och kräver
estate-policy-beslut — dokumenterad separat, hålls UTANFÖR denna merge så
koden kanoniseras utan blockering. Härdningens nya tester är exekverade
lokalt: real-Postgres 5/5 (DATABASE_URL-aktiverad outbox).
2026-09-07 19:35:29 +02:00
admin 3edc56dcdb fix: slutgranskning av dataset/search/ER-ytorna + STATUS-sanning
Security Scan (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / integration (push) Successful in 29s
CI (SIAX Cloud) / quality (push) Successful in 48s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / security (pull_request) Successful in 28s
CI (SIAX Cloud) / quality (pull_request) Successful in 48s
CI (SIAX Cloud) / integration (pull_request) Successful in 55s
Python Engine CI (SIAX Cloud) / python-engine (push) Failing after 4m52s
Python Engine CI (SIAX Cloud) / python-engine (pull_request) Failing after 4m48s
Slutgate inför merge (per fortsättningsplan):

Kontrakt: CreateDatasetVersionInput.artifact_refs → readonly string[]
(anropare får skicka 'as const'; servicen muterar aldrig); postgres.js
tx.array() får muterbar kopia vid INSERT.

Testkorrigeringar (stale mot starkare implementation — aldrig svagare):
- entity-resolution-http: request(body, undefined) triggade default-param
  och skickade GILTIGT token → 200. Tomt token = 'utan token' → 401 fail-closed.
- entity-resolution: /two records/ → /between 2 and 5000/ (bounds-aware validering)
- search-service: omformat purpose-filter-test + NY negativ kontroll —
  rebuild avvisar dokument utan purpose_tags (fail closed, generation discarded)
- dataset-postgres.realinfra: sätter DATABASE_URL i setup så den durabla
  AUD0-outboxen aktiveras (testet ljög annars om durabilitet) — 5/5 mot live Postgres

STATUS.md: AUD0-klient + lineage-rader (outbox nu real-infra testad),
gap-listan (persistence/routes/outbox stängda, exakt vad som återstår),
P065 STÄNGD med closure-record (thin adapter, v3-semantik, hard-negative
transitivitet, fail-closed 401 — 4/4 planpunkter verifierade).

Verifierat: typecheck EXIT 0 · 945/945 unit · 5/5 real-Postgres · next build EXIT 0
2026-09-07 19:31:22 +02:00
admin e49f809e68 Merge pull request 'fix(descriptor): 0PT operationalState running -> down (measured 2026-09-07)' (#41) from fix/descriptor-0pt-operational-state-down into main
Deploy to Coolify / deploy (push) Successful in 2s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / integration (push) Successful in 28s
CI (SIAX Cloud) / quality (push) Successful in 51s
2026-09-07 17:02:47 +00:00
Simon AxelssonandClaude Opus 5 8dd85ad7cc fix(descriptor): 0PT operationalState running -> down (measured)
CI (SIAX Cloud) / integration (push) Successful in 26s
CI (SIAX Cloud) / quality (push) Successful in 32s
Security Scan (SIAX Cloud) / security (push) Successful in 37s
CI (SIAX Cloud) / security (push) Successful in 37s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 14s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / integration (pull_request) Successful in 30s
CI (SIAX Cloud) / quality (pull_request) Successful in 56s
Both public 0PT hosts are dead as of 2026-09-07:

  $ curl -sSI https://0pt.app/
  HTTP/2 402 ... server: Vercel ... x-vercel-error: DEPLOYMENT_DISABLED
  (identical on /api/health and /api/ready)

  $ curl -sSI https://api.0pt.app/health
  HTTP/2 404 ... server: Vercel ... x-vercel-error: DEPLOYMENT_NOT_FOUND

siax.repo.json claimed operationalState "running"; siax.repo.v3.json
claimed "degraded" on the strength of a 2026-09-04 probe where
/api/health still answered 200. Neither holds now, so both files move to
"down" and both domain entries record the probe that motivated it.

Also recorded: both names resolve into Vercel address space
(216.150.16.193 / 216.150.1.1 and 216.150.1.129 / 216.150.16.65), not
the Hetzner fleet.

No DNS, deploy or provider setting was touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:50:38 +02:00
Simon AxelssonandClaude Opus 5 d428dd5018 feat(deploy): gör 0pt körbar utanför Vercel (standalone + bevisad Docker-image)
Security Scan (SIAX Cloud) / security (push) Successful in 17s
CI (SIAX Cloud) / security (push) Successful in 26s
CI (SIAX Cloud) / integration (push) Successful in 30s
CI (SIAX Cloud) / quality (push) Successful in 37s
CI (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / integration (pull_request) Successful in 25s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 26s
CI (SIAX Cloud) / quality (pull_request) Successful in 50s
0pt.app svarar i dag HTTP 402 DEPLOYMENT_DISABLED (Vercels betalningsspärr) och
har ingen självhostad ersättare igång. Det här gör appen faktiskt byggbar och
körbar på Coolify. Referens: sax3l/siax-io, som redan kör självhostat på flottan
— dess Dockerfile återanvänds i form i stället för att uppfinna ett eget mönster.

next.config.mjs:
  * output: "standalone" — runtime-imagen kör `node server.js` i stället för att
    släpa med pnpm, corepack och hela node_modules-trädet.
  * images.unoptimized: true BORTTAGET. Det var v0-generatorns standardvärde, inte
    ett val: next.config.mjs var orörd sedan "Initial commit from v0". Självhostat
    är rätt lösning att låta Next optimera själv.
  * poweredByHeader: false.

Dockerfile (fyra steg, samma form som siax-io):
  * node:24-alpine -> node:22-alpine. Båda CI-workflowsen bygger på node 22;
    att bygga och köra på samma major som grinden testar tar bort en version-skew.
  * libc6-compat (sharp), icke-root `node`, HEALTHCHECK mot /api/health,
    npm/npx strippat ur runtime-imagen (SIO-019-mönstret).
  * --ignore-workspace borttaget: motiveringen i kommentaren var inaktuell sedan
    P1-21 (pnpm-workspace.yaml har ett giltigt packages:-fält och
    packages/schemas är en riktig medlem). Containerinstallationen blir därmed
    bit för bit samma kommando som CI kör.
  * --prod=false: Coolify injicerar NODE_ENV=production vid byggtid, och pnpm
    hoppar då över devDependencies som next build kräver.

Sharp levereras i ett eget npm-steg, och det är inte godtyckligt:
next build spårar INTE sharp in i .next/standalone (verifierat: standalone-
utdatans node_modules innehöll bara next/, react/, react-dom/). Den uppenbara
lösningen outputFileTracingIncludes fungerar bevisligen inte — globben
"./node_modules/@img/**/*" får Turbopack att panika på pnpms katalogsymlänkar
("Is a directory (os error 21)") och bygget faller med exit 1. Reproducerat, inte
antaget. npm-steget lägger ett platt, symlänkfritt träd som runtime-steget kan
kopiera rakt av, pinnat till versionen i pnpm-lock.yaml, och faller hårt om
versionen inte går att läsa ut i stället för att tyst skeppa trasig optimering.

BEVISAT, inte påstått (fullständiga exitkoder i PR-beskrivningen):
  * pnpm install --frozen-lockfile -> 0; next build med HELT TOM env -> 0
  * docker build --no-cache -> 0; container startar, /api/health -> HTTP 200
  * /api/ready utan DATABASE_URL -> HTTP 503 (faller stängt, som avsett)
  * /api/0pt/* utan Bearer -> HTTP 401 (middleware kör självhostat)
  * /_next/image -> HTTP 200 image/avif, 1 488 706 B PNG -> 51 161 B (29x)
  * sharp laddar i runtime-imagen (libvips 8.18.6, musl-binärer)
  * icke-root uid=1000, HEALTHCHECK "healthy", image 1,33 GB -> 423 MB
  * typecheck 0, test 0 (930 passerade). lint/prettier faller identiskt på ren
    main => pre-existerande, inte infört här. Ingen grind har rörts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:50:14 +02:00
admin e2437ab09e docs(er): reconcile ecosystem acquisition plan with canonical ER architecture
CI (SIAX Cloud) / security (push) Successful in 16s
CI (SIAX Cloud) / quality (push) Failing after 19s
Security Scan (SIAX Cloud) / security (push) Successful in 32s
CI (SIAX Cloud) / integration (push) Failing after 49s
Python Engine CI (SIAX Cloud) / python-engine (push) Failing after 5m34s
2026-09-07 18:22:26 +02:00
admin 93c01d2264 fix(er): refuse score-only matches at Python merge boundary 2026-09-07 18:18:33 +02:00
admin d0cba02ee0 feat: expose idempotent N0D-backed batch ER submission 2026-09-07 18:18:23 +02:00
admin 7d11ea895c feat: expose generic tenant-safe ER candidate API 2026-09-07 18:18:12 +02:00
admin 35a8ff0f2a feat: add generic ER composition root 2026-09-07 18:18:02 +02:00
admin 243918a255 feat: harden canonical ER service and idempotent batch submission 2026-09-07 18:17:52 +02:00
admin 9782eaf42c refactor: share ER request validation across HTTP surfaces 2026-09-07 18:17:00 +02:00
admin 00e4636655 refactor: centralize ER request validation 2026-09-07 18:16:43 +02:00
admin 6f525c5c9e fix: pass registration country into canonical company identity rules 2026-09-07 18:15:47 +02:00