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
1 change: 0 additions & 1 deletion .github/secret_scanning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
# Keep forge secret scanning on real leaks.
paths-ignore:
- "tests/**"
- "src/traust_engine/data/secure-code-audit/gitleaks-rules/**"
- "src/traust_engine/data/secure-code-audit/opengrep-rules/**"
57 changes: 0 additions & 57 deletions .ratchet.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,18 @@
"src/traust_engine/_ops_base.py": {
"contracts": 1
},
"src/traust_engine/_util/safe_exec.py": {
"contracts": 1
},
"src/traust_engine/adapters/_contract_bridge.py": {
"contracts": 2
},
"src/traust_engine/adapters/checkov.py": {
"contracts": 1
},
"src/traust_engine/adapters/gitleaks.py": {
"contracts": 2
},
"src/traust_engine/adapters/govulncheck.py": {
"contracts": 1
},
"src/traust_engine/adapters/grype.py": {
"contracts": 1
},
"src/traust_engine/adapters/joern.py": {
"contracts": 1
},
"src/traust_engine/adapters/opengrep.py": {
"contracts": 2
},
"src/traust_engine/adapters/ops.py": {
"contracts": 1
},
"src/traust_engine/adapters/osv.py": {
"contracts": 1
},
"src/traust_engine/adapters/yara.py": {
"contracts": 1
},
"src/traust_engine/compliance/dashboard.py": {
"contracts": 2,
"database": 1
},
"src/traust_engine/compliance/ops.py": {
"contracts": 1
},
"src/traust_engine/compliance/scope.py": {
"contracts": 1
},
"src/traust_engine/corpus/resolver.py": {
"contracts": 2,
"state-file": 2
Expand Down Expand Up @@ -77,35 +46,12 @@
"src/traust_engine/portfolio/graph.py": {
"database": 1
},
"src/traust_engine/registry/feeds.py": {
"contracts": 1
},
"src/traust_engine/registry/models.py": {
"contracts": 1
},
"src/traust_engine/registry/ops.py": {
"contracts": 1
},
"src/traust_engine/registry/products.py": {
"contracts": 1
},
"src/traust_engine/reporting/lint.py": {
"contracts": 1
},
"src/traust_engine/reporting/render.py": {
"contracts": 1
},
"src/traust_engine/reporting/sarif.py": {
"contracts": 1,
"state-file": 4
},
"src/traust_engine/reporting/threat_rating.py": {
"contracts": 1
},
"src/traust_engine/reporting/validate.py": {
"contracts": 3,
"state-file": 3
},
"src/traust_engine/sweep/engine.py": {
"contracts": 1
},
Expand All @@ -114,8 +60,5 @@
},
"src/traust_engine/sweep/rule_lane.py": {
"contracts": 1
},
"src/traust_engine/toolchain/ops.py": {
"contracts": 1
}
}
6 changes: 1 addition & 5 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
# Disposition ledger and corpus resolution
/src/traust_engine/corpus/ @traust-security/traust-admins

# Finding identity (traust-ledger) and report integrity validation
/src/traust_engine/_util/finding_identity.py @traust-security/traust-admins
/src/traust_engine/_util/safe_exec.py @traust-security/traust-admins
# Metrics journal
/src/traust_engine/metrics/history.py @traust-security/traust-admins
/src/traust_engine/reporting/validate.py @traust-security/traust-admins
/tests/test_validate_report.py @traust-security/traust-admins

* @traust-security/traust-admins
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Direct downstream: `traust`.

```bash
make test # unit tests (no external binaries needed)
uv run pytest -q # full suite (integration needs gitleaks/opengrep)
uv run pytest -q # full suite (integration needs opengrep)
```

## Architecture
Expand Down
49 changes: 18 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,28 @@
# traust-engine

Processing library for Traust: scanner adapters, report tooling and deterministic
workflows. Finding identity, disposition and persistence belong to traust-core,
not the engine or app CLI. Import as `traust_engine`.
The continuous-ops service for Traust, on traust-core: `traust_engine.ops` runs a
pack's assets through traust-core services. Finding identity, disposition,
persistence, tools and reporting belong to traust-core. Import as `traust_engine`.

## Architecture

| Module | Role |
|---|---|
| `traust_engine.validation` | Scope enforcement and soundness gates |
| `traust_engine.sweep.calibration` | Rule-pack calibration library API |
| `traust_engine.adapters` | Scanner adapters (gitleaks, opengrep, …) |
| `traust_engine.reporting` | Report validation, SARIF, render |
| `traust_engine.ops` | Continuous ops: `Pack` (the pack's `assets.yaml`, checked against contracts `config/v1/pack`), the tick, admission and the reaper (`EngineLoop.run_once`), all through traust-core services |

Finding identity, disposition and persisted finding reads belong to
`traust_core.v1.services.findings`; the old engine cumulative replay is retired.
Scanner adapters keep tool identity in `metadata.tool`, not finding `origin`.
Native scanner fingerprints remain native scanner data, never invented Traust
identity stamps. Supplied finding classifier/dependency metadata survives the
typed bridge, and unknown severity or undeclared top-level fields are refused.
Final artifact admission goes through core's `AdapterResultArtifact` and
`ArtifactPublisher`; sparse scanner claims are not padded into audit findings.

Native scanner results use the adapter-specific observation contract.
Unreported CWEs/description/remediation stay unreported; shared supplied-value
constraints remain enforced. Authored report findings keep their strict schema.
`tests/test_native_adapter_artifact.py` runs the real binary directly through
`AdapterResultArtifact.from_document` without hand-completing fields.
The real bundled token, DSN and encrypted-Vault publication regression also
verifies that storing observations does not create canonical findings/verdicts.

Rule packs ship under `data/secure-code-audit/` (`opengrep-rules/`,
`gitleaks-rules/`). This library ships **no configuration files and never loads
Kept for traust until Shaun's retire-or-port decisions land (each package is
tagged `PENDING(decision: …)`); deleted when traust retires or ports it:

| Module | Kept for |
|---|---|
| `traust_engine.engine` | `HarnessEngine` facade: `.metrics`, `.models`, `.adapters`, `.sweep`, `.portfolio` |
| `traust_engine.sweep` | sweep stages: collect, draft, sweep, emit, benchmark, rule lane, mining, calibration |
| `traust_engine.portfolio` | portfolio graph layers |
| `traust_engine.metrics`, `traust_engine.registry` | metrics journal and spend pricing |
| `traust_engine.adapters` | opengrep (sweep stages) and checkov (portfolio graph) |
| `traust_engine.corpus` | the report population the sweep stages read |

The opengrep rule pack ships under `data/secure-code-audit/opengrep-rules/`. This library ships **no configuration files and never loads
config itself — it is a pure consumer.** A caller builds the context once
(`traust_contracts.load_context()`, done for you by
`HarnessEngine.load(config_home=…)`) and the engine receives it *injected*: the
Expand Down Expand Up @@ -107,13 +97,10 @@ holds every config file; edit them there (the AWS/SSH model).
| `locations.yaml` → `progress_tracker` | Metrics journal + dashboard output root |
| `locations.yaml` → `feeds_cache` | Feed cache directory |
| `locations.yaml` → `portfolio_graph` | Portfolio graph DB (defaults under `analysis_results`) |
| `locations.yaml` → `gitleaks_config` | Gitleaks TOML (overrides the bundled default) |
| `locations.yaml` → `opengrep_rules` | Opengrep rule pack dir (overrides the bundled default) |
| `locations.yaml` → `product_definitions` | Product/ownership registry endpoint (optional) |
| `locations.yaml` → `sarif_tool_uri` | SARIF `informationUri` (optional; omitted when unset) |

Secrets and OS/tool standards stay environment-driven (`GITHUB_TOKEN`, signing key
material, `XDG_*`, `JAVA_OPTS`, `SAFE_EXEC_DISABLED`).
material, `XDG_*`, `JAVA_OPTS`).

No config ships in the wheel. Templates for every operational file live in the
harness repo as `config/*.example.*`; `install_traust` copies them into
Expand All @@ -135,7 +122,7 @@ Manual equivalents:
uv run ruff check .
uv run ruff format --check .
uv run pytest -m "not integration" -q # unit tests (no external binaries)
uv run pytest -q # full suite; integration skips when gitleaks/opengrep absent
uv run pytest -q # full suite; integration skips when opengrep is absent
uv build
```

Expand Down
9 changes: 2 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ build-backend = "hatchling.build"
name = "traust-engine"
version = "0.39.3"
license = "Apache-2.0"
description = "Processing core for the AI security harness: scanners, data management, analysis, format handlers"
description = "Continuous-ops service for the AI security harness, on traust-core"
requires-python = ">=3.11"
dependencies = [
"traust-core",
"jsonschema>=4.0",
"referencing",
"pyyaml",
]

Expand Down Expand Up @@ -50,9 +48,8 @@ exclude = ["/.ci-venv", "/.venv"]
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
"integration: tests requiring external binaries (gitleaks, opengrep) on PATH",
"integration: tests requiring external binaries (opengrep) on PATH",
"requires_git: test creates git repos in tmp dirs (skipped when git init is blocked)",
"unbound_safe_exec: skip autouse profile bind; assert fallback or explicit profile_map",
]

[tool.ruff]
Expand All @@ -66,6 +63,4 @@ ignore = ["RUF001", "RUF002", "RUF003"]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["S101", "E741", "E402", "E501", "RUF012"]
"src/traust_engine/reporting/lint.py" = ["E501"]
"src/traust_engine/metrics/history.py" = ["E501"]
"src/traust_engine/reporting/validate.py" = ["E402"]
21 changes: 10 additions & 11 deletions src/traust_engine/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
"""Harness Engine — processing core for the AI security harness.
"""Harness Engine — the continuous-ops service on traust-core.

Submodules:
ops — continuous ops: pack spec, controller (tick), admission, reaper
corpus — population management (discovery, identity, dedup)
metrics — hash-chained metrics recording + spend tracking
portfolio — source-code dependency graph analysis

Kept for traust until its PENDING decisions (sweep stages, portfolio graph
layers, metrics journal) retire or port them:
engine — the ``HarnessEngine`` facade (metrics, models, adapters, sweep, portfolio)
sweep — class-generalization scan engine
impact — language-aware impact analysis
adapters — external scanner wrappers (opengrep, osv, gitleaks, ...)
compliance — compliance scope + boundary resolution
reporting — output format handlers (validate, render, SARIF)
registry — model + product resolution
escaping — public text-safety helpers (HTML, JSON-in-script, md cells, CSV)
_util — leaf utilities (paths, safe_exec, elf, redact)
portfolio — source-code dependency graph analysis
metrics — hash-chained metrics recording + spend tracking
registry — model resolution and spend pricing
adapters — opengrep (sweep stages) and checkov (portfolio graph)
corpus — population resolver the sweep stages read
"""

from traust_engine.assets import harness_version as _harness_version
Expand Down
12 changes: 3 additions & 9 deletions src/traust_engine/_ops_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Holds the injected context and the fail-loud location resolvers every namespace
needs. The resolution logic itself lives in :mod:`traust_engine.locations`; this
just binds it to ``self._ctx.locations`` so no namespace re-derives it.

PENDING(decision: sweep stages | portfolio graph layers | metrics journal) — kept for traust;
deleted when traust retires or ports it.
"""

from __future__ import annotations
Expand All @@ -17,15 +20,6 @@
class ContextOps:
def __init__(self, ctx: HarnessContext) -> None:
self._ctx = ctx
self._safe_exec_profile_map: dict | None = None

def safe_exec_profile_map(self) -> dict:
"""Resolved safe_exec profiles for this context (one per cached *Ops instance)."""
if self._safe_exec_profile_map is None:
from traust_engine._util import safe_exec

self._safe_exec_profile_map = safe_exec.profiles_from_section(self._ctx.safe_exec)
return self._safe_exec_profile_map

def _optional_config_path(self, filename: str, loaded: object | None) -> Path | None:
"""Path under config_home when an optional section was loaded at entry."""
Expand Down
1 change: 0 additions & 1 deletion src/traust_engine/_util/__init__.py

This file was deleted.

Loading
Loading