plugin

package
v0.88.2 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package plugin is the public API a project-local Go extension compiles against. It is the only non-internal Go package in this module, and it exists for one narrow reason.

Go refuses an import of a path containing an "internal" element from outside the tree rooted at that element's parent. `sigcomply build` compiles a customer's .sigcomply/ extensions inside the CUSTOMER's module — readModulePath in cmd/sigcomply/build.go reads the project's own go.mod, and `go build` runs from the project directory. So every interface and registry a Go extension has to reach — core.SourcePlugin, sources.RegisterFactory, vault.RegisterBackend, manual.RegisterReader — sat behind a wall the customer could not climb: their package passed `sigcomply build`'s discovery, validation and vet, and then failed the compile that same command triggered, with "use of internal package … not allowed". Authoring a Go plugin project-locally meant forking the CLI. This package is the door, and nothing more than the door.

Everything here is a compatibility promise

A re-export is a commitment: it is what customers compile against and what a major version has to keep working (see docs/architecture/07-extensibility.md §Compatibility guarantees). The surface is therefore deliberately small — exactly what the three plugin axes documented in docs/architecture/00-three-plugin-axes.md need, and not one identifier more. Adding to it is a decision, not a convenience; the cost of a too-wide façade is paid years later, by whoever cannot change an internal type because someone once found it handy here.

  • Axis C, source plugins: SourcePlugin, Env, SourceFactory, RegisterSource, plus the evidence values a Collect implementation must name (SlotRequest, EvidenceRecord, RecordScope) and the optional caveat interface (CaveatedSource, SourceCaveat).
  • Axis B, vault backends: Vault, Envelope, VaultConfig, VaultFactory, RegisterVaultBackend.
  • Axis A, manual-evidence backends: ManualReader, ManualFileInfo, ManualReaderFactory, RegisterManualReader, ErrManualNotFound.

Aliases, not wrappers

Every type here is a type ALIAS of the internal type, so a value written against this package IS the internal type — identical, not convertible. A plugin built through RegisterSource satisfies core.SourcePlugin with no adapter, records it emits are the same structs the collector validates, and no copy-and-translate layer exists to fall out of step. The registration functions are thin forwarders only because Go has no such thing as a function alias; they add no behavior, and plugin_test.go asserts that a registration made here lands in the registry the orchestrator actually reads.

What is deliberately NOT public

  • Frameworks, policies, the pass_when DSL, the evaluator and the rule registry. Framework specs are curated — an auditor has to trust that the SOC 2 spec being measured against is the canonical one. Custom policies are authored as project-local YAML, and custom rule logic as Rego; neither needs Go.
  • Evidence types. They are registered from JSON Schema — embedded in-tree, or project-locally from .sigcomply/evidence_types/*.json — and never from a Go init(). There is no hook to expose.
  • The aggregation contract (core.SubmissionPayload and friends). That is the privacy boundary: the wire type is structurally incapable of carrying identifiers, and widening it is an upstream change with a security review, never a customer extension.
  • The vault layout, the manifest, and the signing keys. Auditors and the verification SPA depend on those shapes being fixed.
  • The host side of each registry — sources.Build, sources.Lookup, sources.IDs, vault.FromConfig, manual.LookupReader. An extension registers itself; it never dispatches, enumerates or replaces its peers. Keeping the read side internal is what stops a plugin from quietly reaching across the seam into another one.
  • Convenience helpers that happen to be exported internally (sources.StringOpt, the instance-ID grammar, core.EnvelopeSignature). They are one-line idioms or fields reachable through a value that is already public; promising them forever buys nothing.

If something you need is missing, that is a conversation about the contract, not a gap to route around: open an issue rather than vendoring or forking. The data-driven routes (YAML policies, Rego rules, JSON evidence types) need no Go at all and load at every `sigcomply check` — reach for those first.

Index

Constants

This section is empty.

Variables

View Source
var ErrManualNotFound = manual.ErrNotFound

ErrManualNotFound is the sentinel a ManualReader returns when the requested key does not exist. Returning it is not optional: it is what separates missing-but-expected evidence (the policy fails with a structured message telling the operator which folder is empty) from a transport failure (the policy becomes status=error). Any other error is read as transport.

It is a variable rather than a constant only because Go has no error constants; it is the same value as the sentinel the manual.pdf source compares against, so errors.Is works across the seam. Do not reassign it.

Functions

func RegisterManualReader

func RegisterManualReader(id string, factory ManualReaderFactory)

RegisterManualReader registers a manual-evidence backend under id, to be called from the extension package's init(). Duplicate IDs panic at process start, for the same reason RegisterSource's do.

func RegisterSource

func RegisterSource(id string, factory SourceFactory, configKeys ...string)

RegisterSource registers a source-plugin factory under id, to be called from the extension package's init(). Duplicate IDs panic at process start: an in-tree duplicate is a programming error, and a project-local plugin claiming a reserved ID is a misconfiguration the build should not let through.

configKeys names every key the factory reads out of Env.Config. It is optional and fail-open — a factory that declares none is never warned about — but declaring them is what lets the planner report a typo in `sources:` instead of silently collecting nothing, because the inner config bag is an untyped map the config loader cannot check.

func RegisterVaultBackend

func RegisterVaultBackend(id string, factory VaultFactory)

RegisterVaultBackend registers a vault backend under id, to be called from the extension package's init(). Duplicate IDs panic at process start, for the same reason RegisterSource's do.

Types

type CaveatedSource

type CaveatedSource = core.CaveatedSource

CaveatedSource is the optional interface a SourcePlugin implements to declare its SourceCaveats. A plugin that implements nothing declares no caveats, which is the correct default.

type Env

type Env = sources.Env

Env carries everything a SourceFactory needs: Config is the raw map from the project config's `sources:` entry for this plugin, and FrameworkExtras is the escape hatch for framework-supplied data (the manual catalog, for instance). There is deliberately no Vault field — a plugin that needs storage configures its own backend rather than borrowing the run's evidence vault.

type Envelope

type Envelope = core.Envelope

Envelope is the signed wrapper around a batch of EvidenceRecords that a Vault's PutEnvelope receives. It is self-contained — public key and signature travel inside it — so an auditor holding one file can verify it offline; a backend stores the bytes and must not rewrite them.

type EvidenceRecord

type EvidenceRecord = core.EvidenceRecord

EvidenceRecord is one observation a plugin returns from Collect. The Payload is validated against the registered JSON Schema of Type before it is wrapped in a signed envelope; the first non-conforming record fails the binding.

type ManualFileInfo

type ManualFileInfo = manual.FileInfo

ManualFileInfo describes one file returned by ManualReader.List. Key is the full path as passed to Get — prefix-relative, not a bare filename — so a List result feeds straight back into Get.

type ManualReader

type ManualReader = manual.Reader

ManualReader is the read-only interface the manual.pdf source uses to fetch customer-uploaded evidence files. It is named ManualReader rather than Reader because this package holds all three axes at once, and an unqualified Reader beside a Vault and a SourcePlugin would not say which storage it reads.

type ManualReaderFactory

type ManualReaderFactory = manual.ReaderFactory

ManualReaderFactory builds a ManualReader from the raw `manual.pdf` config map, returning the reader plus the (scheme, bucket, prefix) triple used to build the URI recorded in emitted evidence records.

type RecordScope

type RecordScope = core.RecordScope

RecordScope is the account/region/project an EvidenceRecord was collected from — provenance for an auditor reading a single envelope, not a dimension of record identity. Optional; most records leave it nil.

type SlotRequest

type SlotRequest = core.SlotRequest

SlotRequest is the per-binding call into Collect. AcceptedTypes is the intersection of the slot's accepts list with this plugin's Emits(), so a plugin emitting several types dispatches on it (via its Accepts method) rather than on PolicyID, which is diagnostics only.

type SourceCaveat

type SourceCaveat = core.SourceCaveat

SourceCaveat is a plugin's own declaration that a field it emits is a safe default rather than a measurement — the vendor publishes no API for it, or the configured credential cannot reach the one that exists. It is advisory: a caveat never changes a status, a count, or the wire payload.

type SourceFactory

type SourceFactory = sources.Factory

SourceFactory builds a configured plugin instance. It runs once per registered source ID at the start of every `sigcomply check`; an error here is a configuration error (exit code 3).

type SourcePlugin

type SourcePlugin = core.SourcePlugin

SourcePlugin is the interface a source plugin implements: ID, Emits, Init, Collect. Implementations must sort emitted records by ID, set IdentityKey where the evidence type has a cross-source identity, and leave fetch time to EvidenceRecord.CollectedAt — the full contract is documented on core.SourcePlugin.

type Vault

type Vault = core.Vault

Vault is the customer-side persistence layer a backend implements: append-only per run, written by the CLI and read by auditors and dashboards. The CLI never reads back from the vault during the same run.

type VaultConfig

type VaultConfig = spec.VaultConfig

VaultConfig is the project config's `vault:` section: Backend selects the registered backend ID and Config carries every other key through untouched, so a new backend reads its own settings with no typed field and no central validation switch to edit. Str and Bool read Config.

type VaultFactory

type VaultFactory = vault.Factory

VaultFactory builds a fully Init'd Vault from the project's vault config. Backends translate VaultConfig into their own options, then construct and initialize before returning.

Jump to

Keyboard shortcuts

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