mcpacceptance

package
v1.0.217 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package mcpacceptance implements an operator-runnable, artifact-bound Observe Acceptance Harness for the Culvert MCP Gateway (QUAL-6).

The harness drives a BUILT culvert binary through its REAL production boundaries — a real TLS/mTLS listener, real OAuth authentication, the real Admin HTTP API, real /metrics, and the real on-disk encrypted telemetry spool and archive — and emits a deterministic, tamper-evident, secret-free evidence bundle bound to the exact tested artifact.

It is strictly an ACCEPTANCE TEST HARNESS: it never begins Observe, never calls BeginWindow, never creates a qualification-duration window, never promotes a Catalog tool, never enables the executor/upstream/credential broker, never materializes a credential, never alters rollout mode, and never unlocks Production. Every "live" criterion is proven at the production binary boundary, never by calling an internal Go constructor.

Index

Constants

View Source
const EvidenceSchemaVersion = 2

EvidenceSchemaVersion is the schema version of the acceptance evidence bundle. Bump only on a breaking change to the on-disk bundle shape.

v2 (QUAL-6.1) adds the effective-environment proof fields to the summary: effective_bind_host, operator_policy_digest, telemetry ownership/node id, and the supervision descriptor. These are additive, safe (secret-free) fields; a v1 reader simply does not see them. The interpretation of the existing v1 fields is unchanged.

View Source
const HarnessVersion = "qual6-observe-acceptance/1"

HarnessVersion is the acceptance-harness contract version (independent of the tested artifact's version).

Variables

This section is empty.

Functions

This section is empty.

Types

type ArtifactIdentity

type ArtifactIdentity struct {
	Path          string `json:"path"`
	Digest        string `json:"digest"`        // sha256:<hex> of the on-disk binary
	Version       string `json:"version"`       // from GET /healthz
	SourceCommit  string `json:"source_commit"` // operator-supplied / provenance-bound
	Verification  string `json:"verification"`  // "digest-match" | "provenance-bound" | "unverified"
	Authoritative bool   `json:"authoritative"`
}

ArtifactIdentity binds the acceptance result to the exact tested artifact.

type ArtifactSpec

type ArtifactSpec struct {
	BinaryPath           string          `json:"binary_path"`
	ExpectedDigest       string          `json:"expected_digest,omitempty"` // sha256:<hex>
	ExpectedVersion      string          `json:"expected_version,omitempty"`
	ExpectedSourceCommit string          `json:"expected_source_commit,omitempty"`
	Provenance           *ProvenanceSpec `json:"provenance,omitempty"`
}

ArtifactSpec identifies the binary under test and the authoritative-verification material. For an authoritative run, ExpectedDigest and Provenance are mandatory.

type CriterionResult

type CriterionResult struct {
	ID       string   `json:"id"`
	Name     string   `json:"name"`
	Group    string   `json:"group"`
	Required bool     `json:"required"`
	Status   Status   `json:"status"`
	Expected string   `json:"expected"`
	Observed string   `json:"observed"`
	Reason   string   `json:"reason,omitempty"`
	Evidence []string `json:"evidence,omitempty"`
	StartMS  int64    `json:"start_ms"`
	EndMS    int64    `json:"end_ms"`
}

CriterionResult is the bounded, secret-free record of one acceptance criterion. Observed carries only a safe classification (a status code, a bounded reason code, a count) — never a token, key, raw argument, tool output, or path secret.

type Duration

type Duration time.Duration

Duration is a JSON-friendly time.Duration ("30s", "2m").

func (Duration) MarshalJSON

func (d Duration) MarshalJSON() ([]byte, error)

MarshalJSON renders the duration as its string form ("30s").

func (*Duration) UnmarshalJSON

func (d *Duration) UnmarshalJSON(b []byte) error

UnmarshalJSON accepts a duration string ("30s", "2m") or a bare number of seconds.

type EnvSpec

type EnvSpec struct {
	BindHost          string   `json:"bind_host"`
	OAuthIssuer       string   `json:"oauth_issuer"`
	CanonicalResource string   `json:"canonical_resource"`
	RequiredScopes    []string `json:"required_scopes"`
	AcceptedClientIDs []string `json:"accepted_client_ids"`
	TenantA           string   `json:"tenant_a"`
	TenantB           string   `json:"tenant_b"`
	ServerA           string   `json:"server_a"`
	ServerB           string   `json:"server_b"`
	// Identity material by path (public + private references stay on disk, never
	// enter the evidence bundle).
	TLSCertFile    string `json:"tls_cert_file"`
	TLSKeyFile     string `json:"tls_key_file"`
	ServerCAFile   string `json:"server_ca_file"`   // CA the harness trusts for the listener TLS
	ClientCAFile   string `json:"client_ca_file"`   // mTLS client CA the listener requires
	ClientCertFile string `json:"client_cert_file"` // mTLS client cert (for the mTLS scenario)
	ClientKeyFile  string `json:"client_key_file"`
	TrustedJWKS    string `json:"trusted_jwks_file"`
	// SigningKeyFile is the ES256 private key (PEM) the harness uses to mint the
	// tenant-A/tenant-B bearer tokens for the run. It is a file reference; its bytes
	// never appear in evidence.
	SigningKeyFile string `json:"signing_key_file"`
	SigningKID     string `json:"signing_kid"`

	// ── QUAL-6.1 authoritative controls ─────────────────────────────────────────
	// GatewayPort is the operator-selected MCP Gateway listener port on the primary
	// (proc A). The Gateway binds BindHost:GatewayPort; the harness (and any external
	// supervisor) reaches the MCP boundary there. Auxiliary/negative-control processes
	// bind ephemeral ports on the same host.
	GatewayPort int `json:"gateway_port"`
	// TLSServerName is the server-name the harness validates the listener TLS cert
	// against. Optional; empty defaults to BindHost. The operator's server cert SAN
	// must cover it, otherwise the TLS scenario fails truthfully.
	TLSServerName string `json:"tls_server_name,omitempty"`
	// QualificationPolicyFile is the operator-owned Culvert qualification policy file
	// (the SAME production format the binary consumes at mcp.gateway
	// .qualification_policy_file). The harness passes THIS file into the spawned
	// config verbatim and never rewrites it; it never substitutes the dev fixture
	// policy in authoritative mode. Only its digest and the resulting runtime
	// revision/snapshot-hash enter evidence, never its source bytes.
	QualificationPolicyFile string `json:"qualification_policy_file"`
	// Telemetry is the operator-owned QUAL-3 durable-telemetry custody boundary. The
	// harness consumes these production fields on the primary EXACTLY, never a
	// temp-work-root equivalent, never generates or reads the KEK, and never deletes
	// these paths on cleanup.
	Telemetry *TelemetryEnv `json:"telemetry"`
	// Supervision is the operator-accessible Admin + metrics boundary for live
	// external supervision of the primary during the run. Credentials are file
	// references only; their bytes never enter evidence.
	Supervision *SupervisionEnv `json:"supervision"`
}

EnvSpec is the operator-provided qualification environment. Every field is an operator DECISION; the harness never invents hosts, issuers, tenants, or paths. In authoritative mode the harness consumes each of these values in the spawned artifact and PROVES it was consumed (QUAL-6.1); it never records a value it silently ignores.

type FinalizeError

type FinalizeError struct {
	Stage   string
	Message string
}

FinalizeError classifies why bundle finalization failed.

func (*FinalizeError) Error

func (e *FinalizeError) Error() string

type Fixture

type Fixture struct {
	// contains filtered or unexported fields
}

Fixture is the ephemeral, harness-owned qualification environment used for dev / self-test runs. For an authoritative run the operator supplies this material externally (via EnvSpec); the fixture generator is the non-authoritative path.

func NewFixture

func NewFixture(root string, secrets *SecretScan) (*Fixture, error)

NewFixture builds a complete ephemeral two-tenant fixture under root.

func NewFixtureFromEnv

func NewFixtureFromEnv(root string, env *EnvSpec, secrets *SecretScan) (*Fixture, error)

NewFixtureFromEnv builds a fixture from operator-supplied material (authoritative mode). It reuses the SAME inventory/policy/config renderers as the ephemeral dev path — one strict code path — differing only in the source of the identity material. It never generates keys or trust roots; the operator supplies them.

type Harness

type Harness struct {
	// contains filtered or unexported fields
}

Harness drives a built artifact through the real MCP boundaries and produces the evidence bundle. It owns every child process, tripwire, and temporary secret.

func NewHarness

func NewHarness(spec *Spec, opts Options) (*Harness, error)

NewHarness validates the spec and prepares a harness. The evidence directory is created; a separate temp work directory holds secrets and is never referenced by the evidence bundle.

func (*Harness) Run

func (h *Harness) Run(ctx context.Context) (*Summary, error)

Run executes the full acceptance and returns the finalized summary. The overall status is FAIL if any required criterion fails, does not run, artifact identity is not authoritative when required, the secret scan trips, execution is detected, or cleanup fails. Run never begins Observe, never calls BeginWindow, and never changes rollout state.

type Manifest

type Manifest struct {
	SchemaVersion  int             `json:"schema_version"`
	Entries        []ManifestEntry `json:"entries"`
	ManifestDigest string          `json:"manifest_digest"`
}

Manifest is the per-file digest set plus the overall manifest digest. It makes accidental mutation of the bundle detectable. It is NOT a signature and confers no authorization — the bundle is test evidence, never a rollout receipt.

type ManifestEntry

type ManifestEntry struct {
	File   string `json:"file"`
	Digest string `json:"sha256"`
	Bytes  int64  `json:"bytes"`
}

ManifestEntry is one file's tamper-evidence record.

type Mode

type Mode string

Mode selects the artifact-verification policy.

const (
	// ModeAuthoritative requires a matching expected digest AND provenance binding
	// before any traffic. Its evidence is marked authoritative:true.
	ModeAuthoritative Mode = "authoritative"
	// ModeDev is the CI/self-test path against a locally built binary. Its evidence
	// is unmistakably marked authoritative:false and can never be accepted as
	// qualification evidence. Dev mode NEVER silently satisfies an authoritative run.
	ModeDev Mode = "dev"
)

type Options

type Options struct {
	// SourceSHA is the harness's own source commit (for provenance of the run).
	SourceSHA string
	// Now injects a clock for deterministic tests. Defaults to time.Now.
	Now func() time.Time
	// RunHorizon is the requested overall bounded run timeout (the CLI -timeout).
	// Authoritative pre-run PKI validation requires every qualification certificate
	// chain to remain valid through now+RunHorizon, so material that would expire
	// DURING the bounded run is rejected before any child process starts. Zero
	// means no added horizon (chains are still required to be valid at `now`).
	RunHorizon time.Duration
}

Options configure a harness run.

type Process

type Process struct {
	// contains filtered or unexported fields
}

Process is one running built-binary instance under harness ownership.

type ProvenanceSpec

type ProvenanceSpec struct {
	Verifier       string `json:"verifier"`        // e.g. "cosign-keyless"
	Identity       string `json:"identity"`        // pinned issuer/SAN the operator verified against
	VerifiedDigest string `json:"verified_digest"` // sha256:<hex> the operator verified; must equal the hashed binary
}

ProvenanceSpec carries the result of an out-of-band verification the operator performed with the ACCEPTED verifier (cosign keyless against the pinned identity). The harness does NOT re-implement signature verification; it binds the operator's verified digest to the exact hashed binary. A missing or mismatched provenance block fails an authoritative run — it is never a silent downgrade to non-authoritative.

type RunControl

type RunControl struct {
	StartupTimeout  Duration `json:"startup_timeout"`
	RequestTimeout  Duration `json:"request_timeout"`
	ShutdownTimeout Duration `json:"shutdown_timeout"`
	RestartTimeout  Duration `json:"restart_timeout"`
}

RunControl bounds every wait. Zero fields fall back to safe defaults; values above the strict maximum are clamped down (never up).

type SecretScan

type SecretScan struct {
	// contains filtered or unexported fields
}

SecretScan holds the set of exact sensitive values the harness generated so the finalized bundle can be proven not to contain any of them. It also applies the generic pattern scan. A hit fails the run; only a bounded classification is reported, never the offending value.

func NewSecretScan

func NewSecretScan() *SecretScan

NewSecretScan returns an empty registry.

func (*SecretScan) Add

func (s *SecretScan) Add(label, value string)

Add registers an exact sensitive value under a bounded classification label. Empty and very short values are ignored (they would false-positive on ordinary text and carry no secret entropy).

func (*SecretScan) Scan

func (s *SecretScan) Scan(dir string) ([]Violation, error)

Scan reads every file under dir and reports bounded violations for any known secret value or generic secret pattern found. The offending value is never included — only its classification and the file it appeared in.

type Spec

type Spec struct {
	Mode        Mode         `json:"mode"`
	Artifact    ArtifactSpec `json:"artifact"`
	Environment *EnvSpec     `json:"environment,omitempty"`
	Run         RunControl   `json:"run"`
	EvidenceDir string       `json:"evidence_dir"`
}

Spec is the operator-facing acceptance specification. It references identity material by file path (never inline secrets). In dev mode the environment may be omitted and the harness generates an ephemeral two-tenant fixture.

func LoadSpec

func LoadSpec(path string) (*Spec, error)

LoadSpec reads and validates an acceptance spec JSON file.

func (*Spec) ConfigHash

func (s *Spec) ConfigHash() (string, error)

ConfigHash is a deterministic sha256 over the canonical spec (which references secrets only by path — safe to hash and record).

func (*Spec) Validate

func (s *Spec) Validate() error

Validate enforces the mode/artifact/provenance contract.

type Status

type Status string

Status is the outcome of a single acceptance criterion.

const (
	// StatusPass — the criterion was proven at the required boundary.
	StatusPass Status = "PASS"
	// StatusFail — the criterion ran and did not meet its expected result.
	StatusFail Status = "FAIL"
	// StatusSkip — the criterion is explicitly out of Observe scope (never a
	// required criterion) and was deliberately not run.
	StatusSkip Status = "SKIP"
)

type Summary

type Summary struct {
	SchemaVersion        int                `json:"schema_version"`
	Authoritative        bool               `json:"authoritative"`
	HarnessVersion       string             `json:"harness_version"`
	HarnessSourceSHA     string             `json:"harness_source_sha,omitempty"`
	Artifact             ArtifactIdentity   `json:"artifact"`
	AcceptanceConfigHash string             `json:"acceptance_config_hash"`
	RunID                string             `json:"run_id"`
	StartUTC             string             `json:"acceptance_run_start_utc"`
	EndUTC               string             `json:"acceptance_run_end_utc"`
	Overall              Status             `json:"overall"`
	PolicyRevision       uint64             `json:"policy_revision"`
	PolicySnapshotHash   string             `json:"policy_snapshot_hash"`
	InventoryIdentity    string             `json:"inventory_identity"`
	InventoryRevision    uint64             `json:"inventory_revision"`
	TenantMatrix         []TenantMatrixCell `json:"tenant_matrix"`
	TelemetrySummary     TelemetrySummary   `json:"telemetry_summary"`
	RestartResult        Status             `json:"restart_result"`
	EmergencyDisable     Status             `json:"emergency_disable_result"`
	NonExecution         Status             `json:"non_execution_result"`
	// ── QUAL-6.1 effective-environment proof (v2; safe, secret-free) ──────────────
	// EffectiveBindHost is the host the harness successfully connected the MCP
	// listener on (the operator-selected bind host in authoritative mode). It is
	// recorded only AFTER a successful TLS connection to that host, so it reflects the
	// environment that actually ran, never merely a config value.
	EffectiveBindHost string `json:"effective_bind_host,omitempty"`
	// OperatorPolicyDigest is sha256:<hex> of the operator-supplied qualification
	// policy FILE (authoritative mode only). It binds the operator's policy source to
	// the runtime revision/snapshot-hash without copying the policy bytes into
	// evidence.
	OperatorPolicyDigest string `json:"operator_policy_digest,omitempty"`
	// Supervision is the safe live-supervision descriptor: reachable Admin/metrics/
	// Gateway URLs and credential PATH references (never secret values).
	Supervision *SupervisionInfo  `json:"supervision,omitempty"`
	Criteria    []CriterionResult `json:"criteria"`
	// Notes carries bounded, non-authoritative operator notes (e.g. a documented
	// known limitation such as the absent live user-rule ALLOW tools/call path).
	Notes []string `json:"notes,omitempty"`
}

Summary is the top-level acceptance evidence summary (bundle.json).

type SupervisionEnv added in v1.0.200

type SupervisionEnv struct {
	AdminPort         int    `json:"admin_port"`
	MetricsPort       int    `json:"metrics_port"`
	AdminUser         string `json:"admin_user"`
	AdminPasswordFile string `json:"admin_password_file"`
	MetricsTokenFile  string `json:"metrics_token_file"`
}

SupervisionEnv is the operator-accessible Admin + metrics listener + credential configuration for the primary. Ports are operator-selected so an external supervisor knows where to look; credentials are supplied by PATH only (never a raw secret field). The admin UI and proxy/metrics listeners bind all interfaces (existing product behavior) and stay protected by their own auth + optional IP allowlist.

type SupervisionInfo added in v1.0.200

type SupervisionInfo struct {
	RunID                string `json:"run_id"`
	GatewayURL           string `json:"gateway_url"`
	AdminURL             string `json:"admin_url"`
	MetricsURL           string `json:"metrics_url"`
	AdminUser            string `json:"admin_user"`
	AdminCredentialRef   string `json:"admin_credential_ref"`   // file path only, never the password
	MetricsCredentialRef string `json:"metrics_credential_ref"` // file path only, never the token
	AdminReachable       bool   `json:"admin_reachable"`
	MetricsReachable     bool   `json:"metrics_reachable"`
}

SupervisionInfo is the safe runtime-supervision descriptor for the operator. It carries reachable endpoint URLs, credential PATH references (never the values), and the run id — everything an external supervisor needs to observe the run, and nothing sensitive. It is also written standalone to supervision.json.

type TelemetryEnv added in v1.0.200

type TelemetryEnv struct {
	NodeID     string `json:"node_id"`
	DataDir    string `json:"data_dir"`
	KEKFile    string `json:"kek_file"`
	ArchiveDir string `json:"archive_dir"`
}

TelemetryEnv is the operator-owned QUAL-3 telemetry configuration (production fields). The primary process consumes these paths verbatim; the restart scenario reuses the same data root + KEK + archive to prove durable persistence across a real process restart.

type TelemetrySummary

type TelemetrySummary struct {
	TelemetryReady       bool   `json:"telemetry_ready"`
	DecisionTelemetry    string `json:"decision_telemetry"`
	EncryptionAvailable  bool   `json:"encryption_available"`
	Committed            bool   `json:"decision_committed"`
	DenialAggregated     bool   `json:"denial_aggregated"`
	ExportedAfterRestart bool   `json:"evidence_survived_restart"`
	// Ownership classifies the primary's telemetry custody boundary: "operator" in an
	// authoritative run (operator-owned data_dir/KEK/archive, preserved on cleanup),
	// "harness" in dev (ephemeral, removable). NodeID is the safe logical node id.
	Ownership string `json:"ownership,omitempty"`
	NodeID    string `json:"node_id,omitempty"`
}

TelemetrySummary is the bounded telemetry/spool/export health snapshot.

type TenantMatrixCell

type TenantMatrixCell struct {
	Token       string `json:"token"`  // "A" | "B" (which tenant minted the token)
	Server      string `json:"server"` // "A" | "B" (which tenant owns the addressed server)
	Expected    string `json:"expected"`
	Observed    string `json:"observed"`
	CrossTenant bool   `json:"cross_tenant"`
	Status      Status `json:"status"`
}

TenantMatrixCell records one direction of the two-tenant live matrix.

type Violation

type Violation struct {
	Classification string `json:"classification"`
	Location       string `json:"location"`
}

Violation is a bounded, value-free record of a secret-containment failure.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL