diff --git a/README.md b/README.md index 7a39736..c51eb27 100644 --- a/README.md +++ b/README.md @@ -397,9 +397,11 @@ computations, with no cloud, storage, egress, or recurring-service cost. `sith audit verify-pages [page.json...]` performs the same strict bounded-file and canonical-hash checks one page at a time, then requires one ordered same-workspace, same-snapshot genesis-to-head sequence with no missing, replayed, or swapped page. Success is still -internal consistency, not external authenticity. Paging adds one small audit row, at most 512 -entry reads plus fixed anchors, and one response of egress per page; work is linear in retained -entries and page count, with no object store, queue, worker, or recurring cloud resource. +internal consistency, not external authenticity. The online page route adds one small audit row, +at most 512 entry reads plus fixed anchors, and one bounded response of egress per page. Offline +`verify-pages` instead performs one bounded local read and bounded local SHA-256 verification over +at most 512 entries per page, with no hub request or network egress. Both paths are linear in +retained entries and page count and add no object store, queue, worker, or recurring cloud resource. Responses use `X-Content-Type-Options: nosniff` and the fixed `sith-policy-audit.json` or `sith-policy-audit-page.json` attachment filename. Authentication is bearer-only; neither route @@ -469,10 +471,11 @@ after a ten-minute hold. `deny` and `require-approval` remain valid decisions in not failures. This is a fail-closed PEP symptom, not an external Ardur PDP-latency SLI or SLO. At least twenty aggregate `refused` authentication attempts with zero `accepted` attempts over fifteen minutes, sustained for ten minutes, produce one aggregate warning. Any accepted attempt in -the same window suppresses it. At least one accepted-outcome sample must also have reached the rule -evaluator during the last ten minutes; a missing or stale accepted series stays quiet rather than -turning partial telemetry into a refusal-only claim. This is not proof of brute force, credential -stuffing, account compromise, a specific actor, or a negotiated authentication SLO. +the same window suppresses it. At least one recent scraped sample from the preinitialized +accepted-outcome series must also have reached the rule evaluator during the last ten minutes; this +proves series visibility, not an accepted event. A missing or stale accepted series stays quiet +rather than turning partial telemetry into a refusal-only claim. This is not proof of brute force, +credential stuffing, account compromise, a specific actor, or a negotiated authentication SLO. Chain verification detects retained-row edits, deletion, reordering, broken links, and head mismatch. It does not make a WORM or non-repudiation claim: detecting wholesale replacement by a privileged database owner requires a later externally diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 1892482..3746c9e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -332,6 +332,7 @@ erDiagram string approver string resolved_digest "args + resolved target" timestamp approved_at + timestamp expires_at "DB-derived approved_at + 10 minutes" timestamp consumed_at "nullable, set once" } MEMBERSHIP { @@ -357,9 +358,14 @@ Design points: broaden access through PostgreSQL's OR-composition rule. - **`DECISION` (why-allowed, Ardur) and `AUDITLOG` (what-happened, Sith) are separate** and together form a complete agent-action ledger. -- **`APPROVAL` is mutable in exactly one direction** — its identity and resolved digest are - immutable, while one atomic `consumed_at IS NULL` update spends it. FORCE RLS isolates the row; - the application role cannot delete it or update any other column. +- **`APPROVAL` is mutable in exactly one direction** — its identity, resolved digest, + `approved_at`, and `expires_at` are immutable. PostgreSQL derives + `expires_at = approved_at + interval '10 minutes'`; callers cannot supply it, and a database + constraint plus column privileges reject later drift. One atomic update spends the row only when + `consumed_at IS NULL` and `approved_at <= statement_timestamp() < expires_at`. Missing, + mismatched, future, expired, or already-consumed grants affect no row and return the same stable + unavailable refusal. FORCE RLS isolates the row; the application role cannot delete it or update + any other column. - **`CLUSTER.last_seen` / `FLEET_FACT.observed_at`** are what abstention reads. ## 6. Enforcement pipeline (the PEP) diff --git a/docs/EPICS.md b/docs/EPICS.md index 045398e..3f7cbcd 100644 --- a/docs/EPICS.md +++ b/docs/EPICS.md @@ -2741,9 +2741,11 @@ budget, a page, or a dispatch-success signal. **Implementation note (F10.4g).** A ninth portable warning consumes only the bounded `sith_auth_attempts_total{outcome="accepted|refused"}` counter. It fires when at least twenty aggregate attempts are `refused` and none are `accepted` over fifteen minutes, and the condition -persists for ten minutes. Any accepted attempt suppresses it, and at least one accepted-outcome -sample must have reached the evaluator during the most recent ten minutes. Missing or stale -accepted-series data stays quiet rather than turning incomplete telemetry into a security claim. +persists for ten minutes. Any accepted attempt suppresses it. The freshness guard also requires at +least one recent scraped sample from the preinitialized accepted-outcome series during the most +recent ten minutes; that proves series visibility, not an accepted authentication event. Missing or +stale accepted-series data stays quiet rather than turning incomplete telemetry into a security +claim. The expression aggregates away every source label and emits one fixed warning. It is refusal-only traffic, not a generic refusal ratio, brute-force or credential-stuffing detector, actor attribution, SLO, error budget, page, or complete authentication-monitoring claim, and it adds no diff --git a/docs/adr/0012-opencost-coverage-aware-workspace-rollup.md b/docs/adr/0012-opencost-coverage-aware-workspace-rollup.md index 8ad1743..a21436d 100644 --- a/docs/adr/0012-opencost-coverage-aware-workspace-rollup.md +++ b/docs/adr/0012-opencost-coverage-aware-workspace-rollup.md @@ -45,8 +45,10 @@ workload or arbitrary label would create unstable cross-tenant accounting semant reported. With no report, `observed_at` is absent. No collection time or stale objective is invented. 8. The computation is bounded to 256 scopes, 1,024 facts per scope, 4,096 facts total, 8 MiB of - normalized payload, a 256 KiB result, and an aggregate magnitude derived from the per-fact cost - bound. + normalized payload, and a 256 KiB result. Each of the fifteen cost fields is accumulated and + checked independently: one fact's absolute field value cannot exceed `1,000,000,000,000`, and + one rollup's absolute field total cannot exceed `4,096,000,000,000,000` (the per-fact limit + multiplied by the 4,096-fact limit). ## Consequences diff --git a/docs/runbooks/hub-alerts.md b/docs/runbooks/hub-alerts.md index 3a04d40..468d8ea 100644 --- a/docs/runbooks/hub-alerts.md +++ b/docs/runbooks/hub-alerts.md @@ -96,10 +96,12 @@ degraded. **Meaning.** At least 20 aggregate completed authentication attempts were `refused` and none were `accepted` over 15 minutes, and that condition persisted for 10 minutes. Any accepted attempt in -the same window suppresses the warning. At least one accepted-outcome sample must have reached the -evaluator during the last 10 minutes. The rule stays quiet when that series is absent or stale, -because partial telemetry cannot prove refusal-only traffic. This is an operational symptom, not -proof of brute force, credential stuffing, account compromise, or a specific actor. +the same window suppresses the warning. At least one recent scraped sample from the preinitialized +accepted-outcome series must have reached the evaluator during the last 10 minutes. That sample +proves series visibility, not an accepted authentication event. The rule stays quiet when that +series is absent or stale, because partial telemetry cannot prove refusal-only traffic. This is an +operational symptom, not proof of brute force, credential stuffing, account compromise, or a +specific actor. **Triage.** @@ -234,8 +236,9 @@ threshold and 10-minute hold, and cannot divide by zero. The policy-decision ratio requires 20 aggregate `allow|deny|require-approval|error` decisions and counts only `error` as failure. It aggregates away the closed verb and every source label. The refusal-only authentication warning requires at least 20 aggregate refusals, zero accepted -attempts over the same 15-minute window, at least one accepted-outcome sample during the most recent -10 minutes, and a 10-minute hold. It is deliberately not a refusal ratio: without an +attempts over the same 15-minute window, at least one recent scraped sample from the preinitialized +accepted-outcome series during the most recent 10 minutes, and a 10-minute hold. That sample proves +series visibility, not an accepted event. It is deliberately not a refusal ratio: without an environment-specific baseline, a generic percentage would create an arbitrary security threshold. Missing or stale accepted-series data cannot satisfy the expression. The missing-telemetry warning evaluates the existing traffic-independent `sith_build_info` gauge, diff --git a/docs/specs/E2-readfed-brain-integrations.md b/docs/specs/E2-readfed-brain-integrations.md index 7ae962d..289dbdb 100644 --- a/docs/specs/E2-readfed-brain-integrations.md +++ b/docs/specs/E2-readfed-brain-integrations.md @@ -756,9 +756,10 @@ lenses are covered by an installed connector. Otherwise it **abstains** (§2.6, | R6 node pressure | K8s (Node) | — | K8s Events + cloud autoscaler | **Prometheus** (quantify) | **Kubernetes** (detect) **+ Prometheus** (quantify) + cloud (autoscaler) | **Reading the map:** with only the **Wave-1 core (Kubernetes + Argo + GitHub + Prometheus + a log -store)**, all six rules reach at least a *detect* verdict, and R1/R2/R4/R5/R6 reach *confident*. R3's -confidence needs a log connector. This is why W1 is the daily core — it is precisely the coverage the -six rules need. +store)**, all six rules reach at least a *detect* verdict, and R1/R2/R3/R4/R5 reach *confident*. +R6 reaches detection plus Prometheus-backed quantification; it requires cloud-autoscaler facts for +a *confident* verdict. This is why W1 is the daily core — it provides the common coverage while +keeping cloud-specific R6 confidence conditional on the cloud adapter. ### 4.4 Scope-discipline call-outs (anti-drift, from SCOPE §10) @@ -832,8 +833,9 @@ the plan-renderer forks. - [ ] Every connector in §4.2 declares its **kind** (RA/BR/TA), its **verb subset**, and the **lenses** it feeds; the framework rejects an out-of-taxonomy connector (E12/F12.2). -- [ ] With **only the Wave-1 core** installed, R1/R2/R4/R5/R6 reach a *confident* verdict and R3 - reaches at least *detect* — matching the coverage map (§4.3). +- [ ] With **only the Wave-1 core** installed, R1/R2/R3/R4/R5 reach a *confident* verdict and R6 + reaches detection plus Prometheus-backed quantification; cloud-autoscaler facts are required + for R6 confidence — matching the coverage map (§4.3). - [ ] **Scope discipline holds:** Fluentd/FluentBit expose LIVE health only (no log ingestion through them); Grafana is deep-link only; Helm/Kustomize expose no action verbs in v1. - [ ] Each connector's **mode** (local / hub / both) is honored — a local-only run uses no diff --git a/internal/observability/alert_rules_contract_test.go b/internal/observability/alert_rules_contract_test.go index 947e862..52951a4 100644 --- a/internal/observability/alert_rules_contract_test.go +++ b/internal/observability/alert_rules_contract_test.go @@ -76,7 +76,7 @@ func TestPortableAlertRulesStayBoundedAndStatic(t *testing.T) { severity: "warning", hold: "10m", expr: `sum(increase(sith_auth_attempts_total{outcome="refused"}[15m])) >= 20 and sum(increase(sith_auth_attempts_total{outcome="accepted"}[15m])) == 0 and sum(count_over_time(sith_auth_attempts_total{outcome="accepted"}[10m])) > 0`, summary: "Sith hub authentication traffic is persistently refusal-only", - description: "At least twenty aggregate authentication attempts were refused and none were accepted over fifteen minutes; accepted-outcome telemetry was present during the last ten minutes.", + description: "At least twenty aggregate authentication attempts were refused and none were accepted over fifteen minutes; a recent scraped sample from the preinitialized accepted-outcome series was present during the last ten minutes.", }, "SithHubFederationSnapshotFailureRatioHigh": { severity: "warning", hold: "10m", diff --git a/monitoring/sith-hub.rules.test.yml b/monitoring/sith-hub.rules.test.yml index e37fc1e..e5aa356 100644 --- a/monitoring/sith-hub.rules.test.yml +++ b/monitoring/sith-hub.rules.test.yml @@ -226,7 +226,7 @@ tests: severity: warning exp_annotations: summary: Sith hub authentication traffic is persistently refusal-only - description: At least twenty aggregate authentication attempts were refused and none were accepted over fifteen minutes; accepted-outcome telemetry was present during the last ten minutes. + description: At least twenty aggregate authentication attempts were refused and none were accepted over fifteen minutes; a recent scraped sample from the preinitialized accepted-outcome series was present during the last ten minutes. runbook_url: https://github.com/ArdurAI/sith/blob/dev/docs/runbooks/hub-alerts.md#sithhubauthenticationrefusalonly - eval_time: 26m alertname: SithHubAuthenticationRefusalOnly diff --git a/monitoring/sith-hub.rules.yml b/monitoring/sith-hub.rules.yml index 1d5a9ce..4247f8b 100644 --- a/monitoring/sith-hub.rules.yml +++ b/monitoring/sith-hub.rules.yml @@ -58,7 +58,7 @@ groups: severity: warning annotations: summary: Sith hub authentication traffic is persistently refusal-only - description: At least twenty aggregate authentication attempts were refused and none were accepted over fifteen minutes; accepted-outcome telemetry was present during the last ten minutes. + description: At least twenty aggregate authentication attempts were refused and none were accepted over fifteen minutes; a recent scraped sample from the preinitialized accepted-outcome series was present during the last ten minutes. runbook_url: https://github.com/ArdurAI/sith/blob/dev/docs/runbooks/hub-alerts.md#sithhubauthenticationrefusalonly - alert: SithHubFederationSnapshotFailureRatioHigh diff --git a/sessions/2026-07-16-argocd-application-facts.md b/sessions/2026-07-16-argocd-application-facts.md index 5bf30ae..30de799 100644 --- a/sessions/2026-07-16-argocd-application-facts.md +++ b/sessions/2026-07-16-argocd-application-facts.md @@ -4,7 +4,7 @@ - Effort: standard - Branch: `gnanirahulnutakki/feat/argocd-application-facts` - Issue: `#206` -- Status: locally verified; awaiting signed PR and exact post-merge proof +- Status: landed on `dev` through #208; exact post-merge proof recorded below ## Goal @@ -70,6 +70,16 @@ rejecting query/fragment credentials, local paths, and unsupported schemes. - Notion decision: `3a02637e-db07-8194-8160-e78cb189cc86`. - Notion session: `3a02637e-db07-8143-9bf5-f5629753a902`. +## Landed closure + +- Issue #206 closed after PR #208 merged into `dev` on 2026-07-17. +- Exact signed/DCO feature commit: `73ea5cc970f49b2f1a67730e3a5c42489edb594d`. +- Exact merge commit: `311eb1c6c25f0c7dc76487fe0bedfa3a3dde6054`. +- Hosted PR CI, release, CodeQL, and CodeRabbit checks all passed. +- Exact post-merge `dev` CI: . +- Exact post-merge CodeQL: . +- Post-merge Dependabot, code-scanning, and secret-scanning queues were `0 / 0 / 0`. + Primary compatibility references: - diff --git a/sessions/2026-07-16-hub-spoke-worker-pool.md b/sessions/2026-07-16-hub-spoke-worker-pool.md index 8d19c07..5090558 100644 --- a/sessions/2026-07-16-hub-spoke-worker-pool.md +++ b/sessions/2026-07-16-hub-spoke-worker-pool.md @@ -29,7 +29,7 @@ Bound and parallelize one workspace refresh so unavailable spokes do not delay h - Focused `go test -race ./internal/hubfleet` passed. - Synchronization-heavy cancellation and admission tests passed 100 repeated race-detector runs. -- The four-spoke timeout regression completes in one one-second parallel wave. Its one-worker negative control failed as intended at 4.004 seconds. +- The four-spoke timeout regression completes in a single one-second parallel wave. Its one-worker negative control failed as intended at 4.004 seconds. - Red-team review found and repaired a worker-goroutine panic escape and panic-path worker leak; transport and store panic regressions now prove closed errors, peer cancellation/join, and clean later refreshes. - Independent CodeRabbit review completed twice; the exact final tree returned zero findings across all six changed files. - `make ci` passed formatting, vet, lint with zero findings, vulnerability scanning with no findings, the full race suite, safety scripts, and build. diff --git a/sessions/2026-07-16-kubeconfig-directory-race.md b/sessions/2026-07-16-kubeconfig-directory-race.md index 543144d..723a7f7 100644 --- a/sessions/2026-07-16-kubeconfig-directory-race.md +++ b/sessions/2026-07-16-kubeconfig-directory-race.md @@ -15,8 +15,10 @@ Keep directory import bound to the originally selected directory and prevent val - Open one descriptor-backed `os.Root` after validating the selected directory identity. - Traverse and open entries only through that root. - Verify the opened root and regular files match the identities observed before parsing. -- Reject deferred local credential files and path-based exec commands after the root closes. -- Reject deferred CA, client certificate/key, token-file, and path-based exec reads; embedded data and PATH-based exec commands remain supported. +- Reject deferred local credential files and exec commands that name an absolute or relative + executable path after the root closes. +- Reject deferred CA, client certificate/key, token-file, and executable-path reads; embedded data + and bare exec commands resolved through `PATH` remain supported. - Preserve entry-count, depth, and byte bounds plus relative, content-free diagnostics. - Keep generic table pagination, watch bootstrap bounds, and hub concurrency findings out of this slice. diff --git a/sessions/2026-07-18-e10-auth-refusal-only-alert.md b/sessions/2026-07-18-e10-auth-refusal-only-alert.md index d3ee265..607b855 100644 --- a/sessions/2026-07-18-e10-auth-refusal-only-alert.md +++ b/sessions/2026-07-18-e10-auth-refusal-only-alert.md @@ -20,8 +20,9 @@ inventing a workload-independent ratio, attributing an actor, or claiming attack severity labels plus static annotations. - Stay quiet when the accepted series is missing. Partial telemetry cannot prove refusal-only traffic; the separate missing-telemetry rule remains the metamonitoring signal. -- Require at least one accepted-outcome sample during the most recent 10 minutes. This prevents old - samples in the 15-minute range from satisfying the denominator after accepted telemetry stops. +- Require at least one recent scraped sample from the preinitialized accepted-outcome series during + the most recent 10 minutes. This proves series visibility, not an accepted event, and prevents old + samples in the 15-minute range from satisfying the freshness guard after accepted telemetry stops. - Treat any accepted verifier decision as suppression, even if later workspace authorization denies the request. diff --git a/sessions/2026-07-18-e14-argocd-sync-failure-rule.md b/sessions/2026-07-18-e14-argocd-sync-failure-rule.md index 1131f9a..6e851c7 100644 --- a/sessions/2026-07-18-e14-argocd-sync-failure-rule.md +++ b/sessions/2026-07-18-e14-argocd-sync-failure-rule.md @@ -2,7 +2,7 @@ **Builder:** Gnani Rahul · **Branch:** `gnanirahulnutakki/feat/e14-argocd-sync-rule` -**Slice:** E14 R8 / [#270](https://github.com/ArdurAI/sith/issues/270) · **Status:** local gates and review complete +**Slice:** E14 R8 / [#270](https://github.com/ArdurAI/sith/issues/270) · **Status:** landed on `dev` via [#271](https://github.com/ArdurAI/sith/pull/271) **Base:** `origin/dev` at `22c6caa834442120d61add38009bacc154eda4fd` @@ -103,8 +103,8 @@ kubeconfig authorization; Sith marks the command sensitive and never executes it - A later documentation-inclusive review found two minor README precision gaps: it abbreviated the advisory and did not enumerate every fail-closed graph gate. README now names the exact target-bound command and the workspace, provenance, protocol, identity, closed-payload, - phase/change-kind, event-time, and explicit-coverage requirements. Final clean review remains - required before staging. + phase/change-kind, event-time, and explicit-coverage requirements. At this checkpoint, a final + clean review remained required before staging; the landed closure below records its completion. ## [C] Checkpoint #1 @@ -147,6 +147,25 @@ the child issue, and synchronize the landed Notion and Obsidian checkpoints. ## [C] Checkpoint #2 `2026-07-18/e14-argocd-sync-failure-rule#2` records the hosted-review fixes and repeated local -proof above. Next: final exact-tree secret scan and review, create a second SSH-signed DCO/GSTACK -commit, push it, require fresh exact-head CI/CodeQL plus a clean incremental hosted review, resolve -both original review threads, and only then merge into `dev` for exact post-merge proof. +proof above. At this checkpoint, the next steps were the final exact-tree secret scan and review, a +second SSH-signed DCO/GSTACK commit, fresh exact-head CI/CodeQL, clean incremental hosted review, +thread resolution, and exact post-merge proof. The landed closure below records the hosted and +review outcomes; the later audit note records a fresh scan of the exact landed tree. + +## [L] Landed closure — 2026-07-18 + +- [PR #271](https://github.com/ArdurAI/sith/pull/271) merged exact signed DCO/GSTACK feature commit + `7f243bb57b4f98aba878c3fc1eee917ef234a539` as + `89cffa5cb6f4e51c8c5f4ef9410f323ee044f493`. +- Exact-head [CI](https://github.com/ArdurAI/sith/actions/runs/29652392300) and + [CodeQL](https://github.com/ArdurAI/sith/actions/runs/29652391036) passed before merge. +- Exact post-merge `dev` [CI](https://github.com/ArdurAI/sith/actions/runs/29652751808) and + [CodeQL](https://github.com/ArdurAI/sith/actions/runs/29652752052) passed on the merge commit. +- Final-head hosted CodeRabbit reviewed the delta from + `03fdc34dcb4b90f3ec2f8c61b5ef71c5b6b55794` to the landed feature commit and generated no + actionable comments; the final unresolved review-thread count was zero. +- Issue [#270](https://github.com/ArdurAI/sith/issues/270) closed after verification, with zero + open Dependabot, code-scanning, or secret-scanning alerts. +- The retained pre-merge record documents zero secret candidates in both changed-tree scans. A + 2026-07-22 retrospective Trivy scan of exact landed feature tree + `7f243bb57b4f98aba878c3fc1eee917ef234a539` also returned zero secret findings.