IBEX Harness
DocsBenchmarksBlogChangelogRoadmap
GitHub
IBEX Harness

Documentation

Architecture Decision RecordsADR-0002: Repository foundation bootstrapADR-0003: Branch protection and merge policyADR-0004: Protobuf and code generation policyADR-0005: Postgres migration strategyADR-0006: Auth protobuf contract (`ibex.auth.v1`)ADR-0007: Auth token validation implementationADR-0008: Security scanning and CI quality gatesADR-0009: Permission bitmap layoutADR-0010: Cryptography policyADR-0011: Proxy auth gRPC client and middlewareADR-0012: Proxy request normalization (OpenAI chat)ADR-0013: Proxy input validation and stable error envelopeADR-0014: Core domain migration sequencingADR-0015: Proxy rate limit skeleton (Phase 1)ADR-0016: Proxy agent identity verification (Phase 1)ADR-0017: Request ID and trace context strategy (Phase 1)ADR-0018: Graceful shutdown contract (Phase 1)ADR-0019: OpenTelemetry provider configuration (Phase 1)ADR-0020: Shared package boundaries — `packages/config` and `packages/apierror`ADR-0021: Prometheus Metric Catalog (Phase 1)ADR-0022: Health check contract (Phase 1)ADR-0023: Docs site architecture (Phase 1.5)ADR-0024: Benchmark data publishing modelADR-0025: LLM provider abstractionADR-0026: OpenAI client designADR-0027: Streaming dual-write strategyADR-0028: Auth cache designADR-0029: Token revocation propagation via Redis pub/subADR-0030: Directive versioning strategyADR-0031: System prompt injection strategyADR-0032: Session data model and retentionADR-0033: ClickHouse llm_traces schema and retentionADR-0034: Proxy overhead performance measurement methodologyADR-0035: Chat Idempotency-Key Redis dedupeADR-0038: Context assembly service design and gRPC contractADR-0039: Proxy Postgres ownership for session and directive storesADR-0040: Anthropic provider adapterADR-0041: Model capability registryADR-0042: Self-hosted OpenAI-compatible LLM adapterADR-0043: Tokenizer registry architectureADR-0044: Non-streaming response pipelineADR-0045: Streaming response transformationADR-0046: Embedder interface and profile registryADR-0047: Memory temporal validity foundationADR-0048: Memory multi-label categoriesADR-0049: Memory relationship graph readinessADR-0050: MCP server skeleton (transport, auth, audit)ADR-0051: Local LGTM observability stack (Phase 2.5 exit pull-forward)ADR-0052: Memory schema v2 expand (HNSW, quality columns)ADR-0053: Vector store abstraction and composite scoring v2
ADRs›ADR-0008: Security scanning and CI quality gates
ADRs

ADR-0008: Security scanning and CI quality gates

Architecture decision record 0008.

ADR-0008: Security scanning and CI quality gates

  • Status: Accepted
  • Date: 2026-06-02
  • Authors: IBEX Harness team

Context

web/engineering/SECURITY.md §12.2 and web/engineering/DEPENDENCIES.md §9 listed recommended scanners that were not wired in CI. ADR-0003 required only repo-guards, markdownlint, and gitleaks. golangci-lint ran with continue-on-error: true, providing no merge enforcement.

The repo has a single root go.mod, Go services auth and proxy, two Dockerfiles, and no Python/TypeScript application code yet.

Decision

Workflows added

WorkflowPurposePR required check
.github/workflows/codeql.ymlCodeQL (go now; python/javascript when app code exists)CodeQL
.github/workflows/semgrep.ymlIBEX custom rules (hard gate) + community rules (SARIF, non-blocking)semgrep
.github/workflows/scorecard.ymlOSSF supply-chain scoreNo
.github/workflows/sbom.ymlSyft SBOM + Grype scan (CRITICAL); Grype pinned via GRYPE_VERSION with checksum verify; reports as workflow artifacts only (no SARIF upload—Grype SBOM SARIF lacks GitHub artifactLocation)No

CI jobs added or changed (.github/workflows/ci.yml)

JobFailure threshold
trivyCRITICAL/HIGH filesystem CVEs; ignore-unfixed: true
osv-scanCRITICAL/HIGH via OSV reusable workflow
hadolint≥ warning (.hadolint.yaml)
banditHIGH+HIGH when services/memory exists; skip (success) until then; install via hash-pinned .github/requirements/bandit.txt
golangci-lintAny lint issue; single job for auth+proxy; no continue-on-error

Weekly schedule on CI runs only osv-scan (other jobs use if: github.event_name != 'schedule').

CI uses go-version-file: go.mod so the runner Go version tracks go.mod (currently 1.25.13; golang.org/x/crypto ≥ v0.54.0; golangci-lint v2.4+ for Go 1.25).

Go vs JavaScript vulnerability scanning

EcosystemMerge gateToolRationale
JavaScriptosv-scanOSV on pnpm-lock.yamlLockfile advisories with fix versions
Gogovulncheckgovulncheck on packages + auth + proxyReachable stdlib and module vulnerabilities only

osv-scan does not scan go.mod because advisory GO-2026-5932 is module-level for the unmaintained openpgp subpackage (no fixed version; use github.com/ProtonMail/go-crypto/openpgp only if OpenPGP is required). This repo imports only golang.org/x/crypto/argon2 via packages/crypto (ADR-0010). OSV call-analysis cannot mark GO-2026-5932 unexecuted; govulncheck confirms no reachable Go impact. This is not an ignore list — it is the correct tool split for module-level vs reachability advisories.

CodeQL default vs advanced

GitHub Default CodeQL setup conflicts with the advanced .github/workflows/codeql.yml (SARIF rejected). Repo admin must disable Default setup (Settings → Code security → Code scanning → CodeQL → Advanced) before the CodeQL check is reliable.

Dependabot

  • Active: github-actions, gomod at /
  • Deferred (documented in .github/dependabot.yml): pip (/services/memory), npm (/services/dashboard)

Branch protection

.github/branch-protection-main.json requires area gate jobs (stable merge contexts) instead of every individual CI job:

Required checkCovers
ci-gate-reporepo-guards, shellcheck, markdownlint, compose-validate, go-mod-tidy, license-check
ci-gate-goBuf/proto, Go smokes, go-services, golangci-lint, coverage, govulncheck
ci-gate-pythonembedder-test, embedder-coverage
ci-gate-webweb-build
ci-gate-securitytrivy, osv-scan, bandit, hadolint
gitleaksSecret scan (always runs — secrets can appear in any path)
semantic-pr-titleConventional PR title (PRs only)

Gate jobs always run (if: always()). When an area did not change, the gate auto-passes even if child jobs were skipped (see .github/scripts/evaluate-ci-gate.sh). This avoids GitHub branch protection blocking merges when path-filtered jobs are skipped.

Not required for merge (path-scoped or informational): CodeQL, semgrep, dependency-review, scorecard, sbom, individual smoke job names, buf-lint, go-services.

Apply after gate job names have appeared on at least one PR (GitHub rejects unknown check names):

bash
gh api --method PUT \
  repos/Rick1330/ibex-harness/branches/main/protection \
  --input .github/branch-protection-main.json

Path-filtered CI (2026-07)

Heavy jobs run only when their area changed. Filter definitions live in .github/path-filters.yml; all workflows reuse .github/actions/detect-changes.

FilterPaths (summary)Effective flags
goservices/**, packages/**, go.mod, migrations, .golangci.ymlrun_go, run_security, run_docker
pythonservices/**/app/**, services/**/tests/**, Python lockfilesrun_python, run_security
webweb/**, pnpm/turbo root filesrun_web, run_security
protopackages/proto/**(included in go via shared paths)
dockerDockerfiles, .hadolint.yamlrun_docker, run_security
workflows.github/workflows/**, actions, scriptsfull → all areas
depsgo.mod, go.sum, pnpm-lock.yamlfull + run_security
composeinfra/compose/**run_compose
benchmarksbenchmarks/**, web/public/benchmarks/**, benchmark.yml, services/auth/**, services/proxy/**, go.mod, go.sumbenchmark.yml workflow trigger
docs**/*.md, **/*.mdxfast markdownlint only

Cross-cutting rule: workflows or deps changes set full=true and run Go, web, and security scans. workflow_dispatch with force_full: true (nightly, manual) runs the full matrix.

Sibling workflows:

WorkflowPR behavior
codeql.ymlRuns when run_go or run_security; weekly schedule is full Go analysis
semgrep.ymlRuns when run_go or run_web
dependency-review.ymlRuns when deps or run_security
sbom.ymlNo PR trigger — push: main + weekly schedule only
docker-publish.ymlworkflow_run after CI on main skips publish when neither run_docker nor run_go

Safety net (no missed coverage): nightly.yml dispatches full ci.yml with force_full: true (Sun 03:00 UTC); CodeQL and Scorecard weekly schedules; any .github/workflows/** change forces full PR CI.

Validation matrix (run after merge or on a dry-run PR branch):

Test PRExpected heavy jobsGates
web/content MDX onlyweb-build, markdownlint, gitleaksAll gates green; Go jobs skipped
services/proxy Go changeFull Go matrix; no web-buildci-gate-go exercises real jobs
.github/workflows/ci.ymlFull matrixAll gates exercise real jobs
pnpm-lock.yaml onlyweb-build, security scansGo smokes skipped
Dependabot go.mod PRGo + security + web-build (deps sets full=true)All gates green; web-build from deps cross-cut, not from go.mod path alone

PR auto-labeler: .github/workflows/labeler.yml applies area/*, dependencies, and area/infra labels from .github/labeler.yml (sync-labels: true).

AI agent enforcement

  • Custom Semgrep rules encode AGENTS.md / SECURITY.md invariants
  • AGENTS.md for agent security/CI review expectations

Consequences

Positive

  • Unified dependency CVE coverage (OSV) and container/filesystem scanning (Trivy)
  • IBEX-specific invariants enforced mechanically on every PR
  • Supply-chain visibility (Scorecard, SBOM) without blocking solo merge velocity on informational jobs

Negative

  • First PR may fail until CVEs/lint/hadolint findings are fixed
  • Branch protection cannot include new checks until GitHub has seen them on a PR
  • CodeQL requires one-time disable of GitHub Default setup

References

  • CONTRIBUTING.md
  • ADR-0003
  • web/engineering/SECURITY.md §12.2

Was this page helpful?

Edit on GitHub

Last updated on

PreviousADR-0007: Auth token validation implementationNextADR-0009: Permission bitmap layout

On this page

  • Context
  • Decision
  • Workflows added
  • CI jobs added or changed (.github/workflows/ci.yml)
  • Go vs JavaScript vulnerability scanning
  • CodeQL default vs advanced
  • Dependabot
  • Branch protection
  • Path-filtered CI (2026-07)
  • AI agent enforcement
  • Consequences
  • Positive
  • Negative
  • References
0%