Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# .githooks/commit-msg — auto-strip de co-autoria injetada (A.I.I.D.C.O.B.P.P. v1.4).
#
# POR QUE: neste repo NAO existe co-autoria (um autor por commit). A IDE do Cursor
# injeta 'Co-authored-by: Cursor' MESMO com o toggle 'Commit Attribution' OFF —
# a Anysphere admite "toggles sao sugestoes, nao enforceables" (forum #161253, SEV-1).
# Este hook enforca MECANICAMENTE no repo do operador o que o toggle do vendor recusa.
#
# FORWARD-ONLY: mexe so na mensagem do commit ATUAL; nunca reescreve history (a
# evidencia do incidente Cursor no history fica preservada — analise Anysphere/Anthropic).
# BACKSTOP: o gate pytest (tests/test_commit_no_tool_coauthorship.py) e a rede LOUD
# se este hook falhar. Cinturao + suspensorio (nao e "silent fix").
#
# NAO usa --no-verify pra pular isto (proibido ao agente, matriz v1.4). So o HITL,
# na mao, se algum dia quiser um co-autor humano real (raro).
set -euo pipefail

MSG_FILE="${1:?commit-msg hook: falta o arquivo da mensagem}"

# Remove QUALQUER linha 'Co-authored-by:' (case-insensitive). Fail-closed = igual ao gate.
if grep -qiE '^[[:space:]]*Co-authored-by:[[:space:]]*\S' "$MSG_FILE"; then
stripped="$(grep -viE '^[[:space:]]*Co-authored-by:[[:space:]]*\S' "$MSG_FILE")"
printf '%s\n' "$stripped" > "$MSG_FILE"
echo "[commit-msg] co-autoria injetada removida (repo nao co-autora; ver forum #161253)." >&2
fi
exit 0
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ jobs:
# dev group: pytest, hypothesis, pre-commit stack — not shipped to end-user `uv sync` default in CI test matrix
run: uv sync --extra shares --group dev

- name: Install gitleaks (binary; kombi PLAN_NO_COAUTHORSHIP_GATE)
run: |
VER="8.30.1"
BASE="https://github.com/gitleaks/gitleaks/releases/download/v${VER}"
TARBALL="gitleaks_${VER}_linux_x64.tar.gz"
curl -sSfL "${BASE}/${TARBALL}" -o "${TARBALL}"
curl -sSfL "${BASE}/gitleaks_${VER}_checksums.txt" -o gl.sums
grep " ${TARBALL}$" gl.sums | sha256sum -c -
tar -xzf "${TARBALL}" gitleaks
sudo install -m 0755 gitleaks /usr/local/bin/gitleaks

- name: Run tests
run: uv run pytest -v -W error
# addopts in pyproject.toml also set -W error; explicit in CI so tests pass without warnings.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gitleaks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
curl -sSfL "${BASE}/gitleaks_${VER}_checksums.txt" -o gl.sums
grep " ${TARBALL}$" gl.sums | sha256sum -c -
tar -xzf "${TARBALL}" gitleaks
./gitleaks git . --no-banner --redact --exit-code 1
./gitleaks git . --config .gitleaks.toml --no-banner --redact --exit-code 1

slack-notify-on-failure:
name: Slack CI failure notify
Expand Down
23 changes: 23 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
title = "data-boar gitleaks config"

# extend + useDefault: mantém TODAS as regras default de segredo (não regride a detecção)
# e ADICIONA a regra de governança abaixo. Sem isso, [[rules]] custom SUBSTITUIria as defaults.
[extend]
useDefault = true

[allowlist]
description = "Confirmed FP 2026-05-18 — synthetic test data and operator howto curl examples"
# FP: chave demo sintetica + fingerprint GPG PUBLICO, nao segredo (allowlist por VALOR, nunca por path)
regexes = [
'''correct-key-12345''',
'''(?i)wrong-key''', # FP: chave FAKE demo (curl-auth-header) no synthetic_corpus:778, commit historico b902a2ce.
'''D6F81740\s*AA5FAB8A\s*CE5716AF\s*871542E6\s*F789F64F''',
'''D6F81740AA5FAB8ACE5716AF871542E6F789F64F''',
]
paths = [
'''scripts/generate_synthetic_poc_corpus\.py''',
'''docs/ops/API_KEY_FROM_ENV_OPERATOR_STEPS\.md''',
Expand All @@ -10,3 +22,14 @@ paths = [
'''docs/ops/SECURE_DASHBOARD_AUTH_AND_HTTPS_HOWTO\.pt_BR\.md''',
'''docs/OPERATOR_NOTIFICATION_CHANNELS\.md'''
]

# ── Governança: NÃO EXISTE CO-AUTORIA (fail-closed, defense-in-depth) ──
# Um commit = UM autor (quem fez). Review != co-autoria. IA = FERRAMENTA, nunca co-autora.
# QUALQUER Co-authored-by = FAIL (sem allowlist — nome de humano é forjável; o agente
# escreveria "Fabio" e furaria). Gitleaks varre CONTEÚDO/diff; a commit-MESSAGE é coberta
# pelo pytest tests/test_commit_no_tool_coauthorship.py (a kombi).
[[rules]]
id = "no-coauthorship-at-all"
description = "PROIBIDO: NAO existe co-autoria neste repo — todo commit tem UM autor (quem fez). IA e FERRAMENTA (nunca co-autora); review != co-autoria. QUALQUER 'Co-authored-by:' = FAIL. Usar o nome do operador/humano sem ser ele = FORJA de identidade = impersonation = crime (org DataBoar). CONSERTE INDO PRA FRENTE: releia git log + ADRs 0046/0047/0049/0079 NA INTEGRA e amend forward SEM o trailer. NUNCA --no-verify nem skip (proibido ao agente). So o HITL, na mao, se precisar."
regex = '''(?im)^[ \t]*Co-authored-by:[ \t]*\S'''
tags = ["governance", "no-coauthorship", "fail-closed", "hitl", "adr-0049", "adr-0079"]
16 changes: 16 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ repos:
entry: uv run pytest tests/test_adr_governance_phase1.py -q -W error
language: system
pass_filenames: false
- id: commit-msg-strip-coauthor
name: strip injected Co-authored-by from commit message (forward-only)
entry: .githooks/commit-msg
language: script
stages: [commit-msg]
pass_filenames: true
- id: no-coauthorship-commit-messages
name: no co-authorship in commit messages (kombi)
entry: uv run pytest tests/test_commit_no_tool_coauthorship.py -q -W error
language: system
pass_filenames: false
- id: gitleaks-detect-config
name: gitleaks detect with repo .gitleaks.toml (kombi)
entry: uv run pytest tests/test_gitleaks_config.py -q -W error
language: system
pass_filenames: false
- id: workflow-security-lint
name: zizmor workflow security lint (optional manual stage)
entry: pwsh -NoProfile -File scripts/workflow-security-lint.ps1 -SkipIfMissing
Expand Down
7 changes: 5 additions & 2 deletions core/demo/synthetic_corpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,11 +770,14 @@ def gen_config_errors(base: Path) -> None:
"targets": [
{"type": "filesystem", "path": "./tests/synthetic_corpus/1_happy"}
],
"api": {"require_api_key": True, "api_key": "correct-key-12345"},
"api": {
"require_api_key": True,
"api_key": "EXAMPLE-PLACEHOLDER-NOT-A-KEY",
},
"report": {"output_dir": "./reports"},
},
"expected_error": "HTTP 401 Unauthorized when calling API with wrong key",
"troubleshoot": "Use X-API-Key: correct-key-12345 no header. "
"troubleshoot": "Use X-API-Key: EXAMPLE-PLACEHOLDER-NOT-A-KEY no header. "
"Para testar: curl -H 'X-API-Key: wrong-key' http://localhost:8088/api/v1/scan",
"test_curl": (
"curl -s -o /dev/null -w '%{http_code}' "
Expand Down
56 changes: 56 additions & 0 deletions docs/adr/ADR-0074-supply-chain-layer1-digest-pins-and-rust-sca.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ADR 0074 — Supply-chain Layer 1: digest pins and Rust SCA

- **Date (UTC):** 2026-06-23
- **Authors:** Fabio Leitao
- **Deciders:** Fabio Leitao

## Status

Proposed

### Status history

- 2026-06-23 — Proposed (materialized to close dangling reference: supply-chain posture #987 cited across CI, Dockerfile, dependabot, grype, and deny.toml since PR #998; ADR file missing — PR #997 touched only INVENTORY.txt).

## Context

The build and release pipeline pulls third-party GitHub Actions, base container images, and Rust crates — each a supply-chain entry point. Without pinning and scanning, a compromised upstream tag or a vulnerable transitive crate can enter a release silently.

[ADR 0005](ADR-0005-ci-github-actions-supply-chain-pins.md) established Action SHA pinning and a pinned **uv** CLI in CI; this ADR records **Layer 1** of the broader supply-chain posture (GitHub #987) and ties together digest-pinned images, Rust SCA, and distroless image scanning already enforced in workflows and tests.

## Decision

Layer 1 of the supply-chain posture is mandatory and mechanical:

1. **Actions pinned to full commit SHAs** — no floating tags in `.github/workflows/*`.
2. **Base image digest pins** — `Dockerfile` `FROM` lines pinned by digest; the Dependabot docker ecosystem proposes digest bumps.
3. **Rust SCA before merge** — `cargo-deny` (`rust/boar_fast_filter/deny.toml`) gates advisories and license drift.
4. **Distroless + Grype gate** — the assembled image is scanned; findings block release.

## Rationale

1. Pinning removes the moving-tag attack surface: a rebuilt CI run resolves the exact bytes reviewed.
2. Rust SCA catches vulnerable transitive crates before they reach a build, not after.

Each layer is additive and does not replace the previous one; Layer 1 is the mechanical floor on which detection layers (L3/L4) rest.

## Consequences

- **Positive:** Reproducible, reviewable supply-chain; no floating upstream.
- **Negative:** Digest/SHA bumps require Dependabot churn and a review cadence.

## Related Decisions

- [ADR 0005 — CI and GitHub Actions supply chain pins](ADR-0005-ci-github-actions-supply-chain-pins.md)
- [ADR 0063 — Ed25519 license JWT signing](ADR-0063-ed25519-license-jwt-signing.md)
- [ADR 0075 — Plugin authentication: file-based vs Bearer](ADR-0075-plugin-auth-file-based-vs-bearer.md)
- GitHub #987 (decision) · #988 (Layer 1 implementation) · #997 (inventory-only merge — the gap)
- [PLAN_IMAGE_HARDENING](../plans/completed/PLAN_IMAGE_HARDENING.md) (completed)

## References

- `tests/test_github_workflows.py` — Layer 1 workflow and Dockerfile guards
- `tests/test_docker_image_hardening.py` — digest-pinned `FROM` stages
- `.github/dependabot.yml` — docker ecosystem digest bumps
- `.grype.yaml` — distroless scan policy
- `rust/boar_fast_filter/deny.toml` — `cargo-deny` policy
5 changes: 3 additions & 2 deletions docs/adr/INVENTORY.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ADR Inventory - generated by scripts/inv-adr.ps1
# GeneratedUtc: 2026-07-04T05:17:52Z
# GeneratedUtc: 2026-07-04T14:53:16Z
# Algorithm: SHA256
# Format: NUMBER | STATUS | FILE_HASH | FILENAME | TITLE | RATIFIED_BY
# RATIFIED_BY: - = N/A; PENDING = ratification line with signature PENDING; @op = stamped
Expand Down Expand Up @@ -76,11 +76,12 @@
0071 | Accepted | 8D6FB89D7247D8E353D30EF14F6C3A281C15BBED9ECF574D2955E220DA8734D8 | ADR-0071-self-protecting-pii-gate.md | Self-protecting PII gate: word-boundary matcher, CODEOWNERS, modification tripwire, sanctioned FP allowlist | @FabioLeitao
0072 | Accepted | 0BE6A85E1154BC9951A0228B5528993471FA37760B1B3B507ABC952AD0045E8C | ADR-0072-commit-gate-vs-release-gate-distinct-criteria.md | Commit Gate vs Release Gate: distinct criteria | @FabioLeitao
0073 | Accepted | C6353A34C1AA2A688373B52E6F90A28576D4C87CFC0D79610B5B425219599982 | ADR-0073-version-scheme-octet-maturity-and-roadmap.md | Version scheme: octet-maturity side-channel + release-line roadmap | -
0074 | Proposed | 8361B02C52B4F4F6EBD0AACFA7BAFB51860132A4659E842F7363201B934CE64F | ADR-0074-supply-chain-layer1-digest-pins-and-rust-sca.md | Supply-chain Layer 1: digest pins and Rust SCA | -
0075 | Proposed | DFB13E4514D8BBC0E5A994FA6D6649C870AF672670D951DB938DBC1BCA13E456 | ADR-0075-plugin-auth-file-based-vs-bearer.md | Plugin authentication — file-based license vs Bearer per-request | -
0076 | Proposed | FD2760FE46D765A060352C48F4B99A892A40846817328691C0DCE29C34E6B25C | ADR-0076-opa-rego-ci-tier-drift-linter-not-runtime.md | OPA/Rego as CI drift linter for commercial tier enforcement (not runtime) | -
0077 | Accepted | F8A4C9D3B2BE2BEE3721C5AE09476F9CD066DB0B58E6B3174D4B783B123A1BAF | ADR-0077-filesystem-scan-no-client-gitignore-by-design.md | Filesystem scan does not honor client `.gitignore` (deliberate design) | -
0078 | Proposed | 5FEF0DCAC3DA292E33519F24FE6387584C04A850771958FF78B19D3EEB856990 | ADR-0078-multi-pattern-regex-benchmark-gate-regexset-before-vectorscan.md | Multi-pattern regex acceleration gated by benchmark (RegexSet before Vectorscan) | -
0079 | Proposed | 158C68D90B9C6934F0FAAC392E86C6C889FA8F5A6E9AD8197168205946435F9D | ADR-0079-ecosystem-engineering-rigor-canon.md | Ecosystem engineering rigor canon (UMADR satellites) | -
0080 | Proposed | 5084990188A98B0454A3FA377C6180DBE5D9CC23B4F71398DBEDFDBB73D31045 | ADR-0080-local-validation-gate-inviolable.md | Local validation gate is inviolable: full check-all (all-greens, zero regressions) before ANY push or PR | -
#
# InventoryHash: 6E7B04DF01C09300B8C43A593786854D90BFA59EFEC6781C09A831BF0573E97A
# InventoryHash: 76DE3B073F0F9AB3A858012E75DFE6876519BC31C3558913C91065AB0633BC3B
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Short, durable notes that capture **why** the project chose an approach—not on
| 0071 | [Self-protecting PII gate: word-boundary matcher, CODEOWNERS, tripwire, FP allowlist](ADR-0071-self-protecting-pii-gate.md) | Accepted |
| 0072 | [Commit Gate vs Release Gate: distinct criteria](ADR-0072-commit-gate-vs-release-gate-distinct-criteria.md) | Accepted |
| 0073 | [Version scheme: octet-maturity side-channel + release-line roadmap](ADR-0073-version-scheme-octet-maturity-and-roadmap.md) | Accepted |
| 0074 | [Supply-chain Layer 1: digest pins and Rust SCA](ADR-0074-supply-chain-layer1-digest-pins-and-rust-sca.md) | Proposed |
| 0075 | [Plugin authentication — file-based license vs Bearer](ADR-0075-plugin-auth-file-based-vs-bearer.md) | Proposed |
| 0076 | [OPA/Rego as CI tier drift linter (not runtime)](ADR-0076-opa-rego-ci-tier-drift-linter-not-runtime.md) | Proposed |
| 0077 | [Filesystem scan does not honor client `.gitignore`](ADR-0077-filesystem-scan-no-client-gitignore-by-design.md) | Accepted |
Expand Down
1 change: 1 addition & 0 deletions docs/adr/README.pt_BR.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Notas curtas e duradouras que registram **por que** o projeto escolheu um caminh
- **0067** — *Reservado* (número liberado; auth de plugin → **ADR-0075** / #769).
- [ADR 0072](ADR-0072-commit-gate-vs-release-gate-distinct-criteria.md) (EN) — **Proposed** — **Commit Gate** (`check-all`/CI) vs **Release Gate** (#406 completão + decisão do operador); vocabulario normativo pós-#970; guarda de maquina (regra 5) em issue filha.
- [ADR 0073](ADR-0073-version-scheme-octet-maturity-and-roadmap.md) (EN) — **Accepted** — octeto-maturidade em `[tool.databoar] maturity_build` (0–127 beta, 128–199 rc, 200–255 release; `.200`=GA, `.201`=fix-1); público **três segmentos**; pós-GA fix na linha `1.7.4` + octeto; próximo público **1.8.0** (sem **1.7.5**); pós-#970/#772/#977.
- [ADR 0074](ADR-0074-supply-chain-layer1-digest-pins-and-rust-sca.md) (EN) — **Proposed** — supply-chain Layer 1: SHAs de Actions, digest no `Dockerfile`, `cargo-deny` (Rust SCA), Grype na imagem distroless; fecha referência pendente de #987.
- [ADR 0075](ADR-0075-plugin-auth-file-based-vs-bearer.md) (EN) — **Proposed** — auth de plugins L2/L3: híbrido (licença file-based + RBAC interno); renumeração de #769.
- [ADR 0065](ADR-0065-nist-sp800228a-api-security-reference.md) (EN) — **Deferido** — NIST SP 800-228A ("Secure Deployment of RESTful Web APIs") como referencia de hardening da API REST; aguardando publicacao final (public comment deadline 2026-07-02; previsto Q3/Q4 2026).
- [ADR 0066](ADR-0066-tampered-state-behavior.md) (EN) — comportamento do estado `TAMPERED`: fail-closed em modo `enforced`; pass-through em modo `monitor`.
Expand Down
1 change: 1 addition & 0 deletions docs/plans/PLANS_HUB.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Do **not** edit the table manually; refresh with `python scripts/plans_hub_sync.
| **Open** | [PLAN_NEXT_WAVE_PLATFORM_AND_GTM.md](PLAN_NEXT_WAVE_PLATFORM_AND_GTM.md) | Plan: Next wave after core trust foundations (platform + GTM) | **Status:** Pending **Date:** 2026-04-02 **Authors:** Fabio Leitao **Priority:** H1 | — |
| **Open** | [PLAN_NORM_TAG_HIERARCHY_AND_DATA_SUBJECT.md](PLAN_NORM_TAG_HIERARCHY_AND_DATA_SUBJECT.md) | Plan: Hierarchical norm_tag + configurable Data-Subject axis | Hybrid slice 1 (#1071): parent→child norm_tag inheritance preserving BR/LGPD vocabulary + optional Data-Subject axis; closes #1069 titular gap. | [PLAN_TAXONOMY_AXES.md](PLAN_TAXONOMY_AXES.md) [PLAN_SUBJECT_CATEGORY_AXIS.md](PLAN_SUBJECT_CATEGORY_AXIS.md) [PLAN_DATA_USE_AXIS.md](PLAN_DATA_USE_AXIS.md) [PLAN_FIDESLANG_EXPORT_ADAPTER.md](PLAN_FIDESLANG_EXPORT_ADAPTER.md) |
| **Open** | [PLAN_NOTIFICATIONS_OFFBAND_AND_SCAN_COMPLETE.md](PLAN_NOTIFICATIONS_OFFBAND_AND_SCAN_COMPLETE.md) | Plan: Off-band notifications and scan-completion notifications | **Status:** Pending **Date:** 2026-03-15 **Authors:** Fabio Leitao **Priority:** H2 | — |
| **Open** | [PLAN_NO_COAUTHORSHIP_GATE.md](PLAN_NO_COAUTHORSHIP_GATE.md) | Plan: No-coauthorship gate (kombi — gitleaks + pytest) | Fail-closed kombi blocking any Co-authored-by trailer in commit messages (pytest) plus governance rule in .gitleaks.toml; A.I.I.D.C.O.B.P.P. v1.4 / ADR-0049 / ADR-0079. | — |
| **Open** | [PLAN_OBJECT_STORAGE_CLOUD_CONNECTORS.md](PLAN_OBJECT_STORAGE_CLOUD_CONNECTORS.md) | Plan: Object storage connectors (S3-class, Azure Blob, GCS) | **Status:** Deferred **Date:** 2026-03-26 **Authors:** Fabio Leitao **Priority:** H2 | — |
| **Open** | [PLAN_OPERATOR_API_KEY_FIRST_AUTH_UX.md](PLAN_OPERATOR_API_KEY_FIRST_AUTH_UX.md) | Plan: Operator API key–first auth UX (reduce JWT / manual Bearer toil) | **Status:** Pending **Date:** 2026-03-29 **Authors:** Fabio Leitao **Priority:** H2 | — |
| **Open** | [PLAN_OPTIONAL_STRONG_CRYPTO_AND_CONTROLS_VALIDATION.md](PLAN_OPTIONAL_STRONG_CRYPTO_AND_CONTROLS_VALIDATION.md) | Plan: Optional strong-crypto validation and inference of anonymisation/controls | **Status:** Deferred **Date:** 2026-03-15 **Authors:** Fabio Leitao **Priority:** H3 | — |
Expand Down
Loading