Compare commits

...
Author SHA1 Message Date
admin e00c7b0fc5 Merge pull request 'docs(runbook): legacy-instansaudit server5 (0pt + L0RE)' (#501) from docs/legacy-instances-20261107 into main
CI (SIAX Cloud) / Component conformance (blocking) (push) Successful in 8s
CI (SIAX Cloud) / security (push) Successful in 16s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / quality (push) Successful in 42s
CI (SIAX Cloud) / sonar (push) Successful in 56s
Release chain (G17, ADR-W16-003) / Build, push, G17 (SBOM/scan/attest/verify/evidence) (push) Successful in 2m25s
Deploy to Coolify / deploy (push) Successful in 2m17s
CI (SIAX Cloud) / integration (push) Successful in 10m2s
CI (SIAX Cloud) / quality (pull_request) In progress
CI (SIAX Cloud) / integration (pull_request) In progress
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 5s
masterplan-lock / check (push) Successful in 7s
CI (SIAX Cloud) / Component conformance (blocking) (pull_request) Successful in 9s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 21s
2026-11-07 17:34:12 +00:00
admin de76f3795b Merge pull request 'fix(canonical): RFC3339-serialisering av timestamptz' (#498) from fix/canonical-iso-timestamps-20261107 into main
CI (SIAX Cloud) / quality (push) Canceled after 5s
CI (SIAX Cloud) / integration (push) Canceled after 5s
CI (SIAX Cloud) / security (push) Canceled after 5s
CI (SIAX Cloud) / sonar (push) Canceled after 5s
CI (SIAX Cloud) / Component conformance (blocking) (push) Canceled after 4s
masterplan-lock / check (push) Successful in 5s
Security Scan (SIAX Cloud) / security (push) Canceled after 5s
Release chain (G17, ADR-W16-003) / Build, push, G17 (SBOM/scan/attest/verify/evidence) (push) Successful in 1m1s
Deploy to Coolify / deploy (push) Successful in 1m12s
2026-11-07 17:34:07 +00:00
admin 3421748f07 Merge branch 'main' into docs/legacy-instances-20261107
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / Component conformance (blocking) (pull_request) Successful in 13s
masterplan-lock / check (pull_request) Successful in 13s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 27s
masterplan-lock / check (push) Successful in 34s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m18s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m29s
2026-11-07 17:19:41 +00:00
admin 9ac681ee27 Merge branch 'main' into fix/canonical-iso-timestamps-20261107
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 4s
masterplan-lock / check (pull_request) Successful in 10s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 20s
CI (SIAX Cloud) / security (pull_request) Successful in 22s
CI (SIAX Cloud) / Component conformance (blocking) (pull_request) Successful in 23s
CI (SIAX Cloud) / integration (pull_request) Successful in 10m0s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m27s
2026-11-07 17:19:39 +00:00
admin cdbb10b8e3 Merge pull request 'test(lint): typa idempotency-store (fixar quality-gaten som blockerar alla PR)' (#503) from fix/lint-siax-access-idempotency into main
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / security (push) Successful in 23s
CI (SIAX Cloud) / Component conformance (blocking) (push) Successful in 26s
Security Scan (SIAX Cloud) / security (push) Successful in 37s
CI (SIAX Cloud) / sonar (push) Successful in 1m22s
Release chain (G17, ADR-W16-003) / Build, push, G17 (SBOM/scan/attest/verify/evidence) (push) Successful in 2m48s
Deploy to Coolify / deploy (push) Successful in 2m55s
CI (SIAX Cloud) / integration (push) Successful in 9m58s
CI (SIAX Cloud) / quality (push) Successful in 10m34s
2026-11-07 17:19:35 +00:00
SIAX Agent 6bbbcf75d4 test(lint): typa idempotency-store i stället för any (blockerar quality-gaten)
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 7s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / Component conformance (blocking) (pull_request) Successful in 15s
CI (SIAX Cloud) / security (pull_request) Successful in 21s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m7s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m22s
tests/siax-access/idempotency.test.ts hade fyra @typescript-eslint/no-explicit-any
vilket fick quality-jobbet att exita 1 (133 testfiler gröna men lint röd) och
därmed blockerade alla PR:er. Använder exporterade IdempotencyStore<unknown,
{x:number}>; eslint rent, 7/7 tester gröna.
2026-11-07 18:15:04 +01:00
admin 7ca7b98fb2 Merge branch 'main' into docs/legacy-instances-20261107
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 5s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
masterplan-lock / check (push) Successful in 26s
CI (SIAX Cloud) / Component conformance (blocking) (pull_request) Successful in 29s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 34s
CI (SIAX Cloud) / integration (pull_request) Successful in 10m30s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m52s
2026-11-07 17:07:45 +00:00
admin 1b7c6c2de9 Merge branch 'main' into fix/canonical-iso-timestamps-20261107
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 11s
masterplan-lock / check (pull_request) Successful in 9s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 14s
CI (SIAX Cloud) / Component conformance (blocking) (pull_request) Successful in 19s
CI (SIAX Cloud) / security (pull_request) Successful in 1m37s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m38s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m10s
2026-11-07 17:07:42 +00:00
SIAX Agent b7627a3a31 docs(runbook): legacy-instansaudit server5 (0pt + L0RE) och disposition
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 3s
masterplan-lock / check (pull_request) Successful in 3s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 15s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m12s
CI (SIAX Cloud) / integration (pull_request) Successful in 9m46s
0pt legacy: 32 kanoniska facts exporterade och återinförda via API (replay
duplicates=32), dump till server11, api/web stoppade med restart=no, pg kvar
för forensik. L0RE-orphan refererad till PR #485. Ingen databas/volymer raderade.
2026-11-07 17:37:33 +01:00
SIAX Agent afd0b4ec46 fix(canonical): serialisera timestamptz som RFC3339 (ISO-8601)
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 5s
masterplan-lock / check (pull_request) Successful in 5s
CI (SIAX Cloud) / security (pull_request) Successful in 25s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 54s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m11s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m1s
queryFacts använde String(Date) -> 'Sat Nov 07 2026 15:00:00 GMT+0000 (...)',
vilket L0RE:s canonical-projection avvisar ('must be RFC3339 date-time').
Inför iso()-helper: Date -> toISOString(), annars String(). Gäller
observed_at, valid_from, valid_to, created_at.
2026-11-07 17:30:40 +01:00
4 changed files with 67 additions and 10 deletions
+47
View File
@@ -0,0 +1,47 @@
# Legacy instance audit — 0pt (server5) and L0RE (server5) — 2026-11-07
Canonical runtimes: **0pt on server6** (Coolify app `shxd6lepxuxfsjsp0ath3z1g`,
`0pt.app`) and **L0RE on server9** (`l0re.siax.io`). This document records the
older instances on server5 and their disposition. It is not production
documentation for either product.
## 1. 0pt legacy (server5)
| Item | Value |
|---|---|
| Containers | `0pt-api` (`0pt-api:c46ebbf`, created 2026-11-05), `0pt-web` (`:18080`) |
| Database | `0pt-pg`, user/db `opt`, 11 MB |
| Exposure | `0pt-web` only on `100.124.7.55:18080`; no DNS record, no reverse proxy |
| Consumers | none found (`/etc/siax`, `/opt/siax`, site0 and L0RE deploy configs) |
| Unique data | 32 canonical facts (30 GLEIF web observations + `body_type` YDL405 + `passmark.find_prime_numbers.v10`) |
**Data reconciliation:** all 32 facts were exported and re-imported through the
canonical API (`POST /api/0pt/canonical/facts`) into the server6 deployment.
Replay returned `duplicates: 32`, so the import is idempotent. Production now
holds 34 facts (32 migrated + 2 verification observations) and 4 entities.
**Backup:** `server5:/var/backups/0pt-legacy/opt_legacy_20261107.dump.zst`
(custom format, 32 KB) + offsite `server11:/home/backup/0pt/`.
**Action taken:** `docker update --restart=no` + `docker stop` for `0pt-api` and
`0pt-web`. `0pt-pg` left running for forensics/rollback. `0pt.app` verified 200
after the stop (served by server6).
**Full removal (requires owner decision):** snapshot/destroy `0pt-pg` volume
after the retention window, remove the legacy compose project, revoke the old
`INTERNAL_TOKEN` if it was ever stored on server5.
## 2. L0RE orphan (server5)
Documented separately in `admin/l0re` PR #485
(`docs/runbook/l0re-orphan-decommission-20261107.md`): API stopped with
`restart=no`, dump + restore proof (8 propositions/62 assertions), no unique
legitimate data (pilot facts already re-projected to production). `l0re-pg` and
`l0re-opensearch` remain for forensics.
## 3. Single-runtime rule
One primary runtime per logical service. A container image of a product running
outside its registered Coolify app is a finding, not a fallback. Both server5
instances were reachable only from the host, which is why the split survived
until this audit.
+1 -1
View File
@@ -13,7 +13,7 @@ BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '0pt_app') THEN
GRANT SELECT, INSERT, UPDATE, DELETE
ON opt_canonical_entities, opt_canonical_facts, opt_canonical_relations
TO 0pt_app;
TO "0pt_app";
END IF;
END
$$;
@@ -30,6 +30,11 @@ export interface CanonicalFactRepository {
queryFacts(query: CanonicalQuery): Promise<CanonicalFact[]>;
}
/** PostgreSQL timestamptz arrives as Date; the API contract is RFC3339/ISO-8601. */
function iso(value: unknown): string {
return value instanceof Date ? value.toISOString() : String(value);
}
export function entityKey(e: CanonicalEntityInput): string {
return `${e.entity_type}\u0000${e.identity_namespace}\u0000${e.identity_value}`;
}
@@ -216,11 +221,11 @@ class PostgresCanonicalFactRepository implements CanonicalFactRepository {
source_record_id: r.source_record_id ?? undefined,
st0re_artifact_id: r.st0re_artifact_id ?? undefined,
aud0_evidence_ref: r.aud0_evidence_ref ?? undefined, run_ref: r.run_ref ?? undefined,
extractor_version: r.extractor_version, observed_at: String(r.observed_at),
valid_from: r.valid_from ? String(r.valid_from) : undefined,
valid_to: r.valid_to ? String(r.valid_to) : undefined,
extractor_version: r.extractor_version, observed_at: iso(r.observed_at),
valid_from: r.valid_from ? iso(r.valid_from) : undefined,
valid_to: r.valid_to ? iso(r.valid_to) : undefined,
confidence: r.confidence === null ? undefined : Number(r.confidence),
quality_status: r.quality_status, status: r.status, created_at: String(r.created_at),
quality_status: r.quality_status, status: r.status, created_at: iso(r.created_at),
})) as CanonicalFact[];
});
}
+10 -5
View File
@@ -1,5 +1,10 @@
import { describe, expect, it } from "vitest";
import { operationFingerprint, operationIdentity, runIdempotentOperation } from "../../packages/siax-access/src/idempotency";
import {
operationFingerprint,
operationIdentity,
runIdempotentOperation,
type IdempotencyStore,
} from "../../packages/siax-access/src/idempotency";
describe("@siax/access universal idempotency", () => {
it("binds every result-affecting input into the fingerprint", () => {
@@ -18,7 +23,7 @@ describe("@siax/access universal idempotency", () => {
});
it("replays a stored receipt verbatim on the exact fingerprint", async () => {
const stored = { x: 1 };
const store: any = {
const store: IdempotencyStore<unknown, { x: number }> = {
start: async () => false,
save: async () => {},
receipt: async () => stored,
@@ -32,7 +37,7 @@ describe("@siax/access universal idempotency", () => {
});
it("claims once and saves only after the dispatch", async () => {
const order: string[] = [];
const store: any = {
const store: IdempotencyStore<unknown, { x: number }> = {
start: async () => { order.push("start"); return true; },
save: async () => { order.push("save"); },
receipt: async () => { order.push("receipt"); return undefined; },
@@ -47,7 +52,7 @@ describe("@siax/access universal idempotency", () => {
expect(order).toEqual(["start", "dispatch", "save"]);
});
it("reports a store error as conflict, never as a fresh start", async () => {
const store: any = {
const store: IdempotencyStore<unknown, { x: number }> = {
start: async () => { throw new Error("db down"); },
save: async () => {},
receipt: async () => { throw new Error("db down"); },
@@ -61,7 +66,7 @@ describe("@siax/access universal idempotency", () => {
expect(dispatched).toBe(0);
});
it("does not rerun the dispatch when start succeeds but save later fails", async () => {
const store: any = { start: async () => true, save: async () => { throw new Error("journal write failed"); }, receipt: async () => undefined };
const store: IdempotencyStore<unknown, { x: number }> = { start: async () => true, save: async () => { throw new Error("journal write failed"); }, receipt: async () => undefined };
let dispatched = 0;
const outcome = await runIdempotentOperation({
store, identity: {}, fingerprint: "fp",