Documentation
¶
Overview ¶
Package hookpins records TOFU content pins for imported hooks at ~/.gridctl/pins/hooks/global.json. A pin is written by the import that installs the hook. A later byte change made any other way is pin drift until a human approves it. gridctl never executes a hook.
Index ¶
- Constants
- Variables
- type ApproveRequest
- type HookDiff
- type HookPin
- type PinFile
- type PinRequest
- type Store
- func (s *Store) Approve(ctx context.Context, name, registryDir string, req ApproveRequest) error
- func (s *Store) CurrentCompositeHash(name, registryDir string) (string, error)
- func (s *Store) Diff(name, registryDir string) (*VerifyResult, error)
- func (s *Store) Get(name string) (*HookPin, bool)
- func (s *Store) Load() error
- func (s *Store) Pin(ctx context.Context, req PinRequest) error
- func (s *Store) Pins() map[string]*HookPin
- func (s *Store) Reset(ctx context.Context, name string) error
- func (s *Store) Sync(ctx context.Context, registryDir string) (*SyncResult, error)
- func (s *Store) Verify(name, registryDir string) (*VerifyResult, error)
- type SyncResult
- type VerifyResult
Constants ¶
const ( // FileVersion is the hook pin file version this binary writes and the // highest version it accepts. FileVersion = "1" StatusPinned = "pinned" StatusDrift = "drift" SourceLocal = "local" SourceGit = "git" )
Variables ¶
var ( ErrCorrupt = errors.New("corrupt hook pin file") ErrNewerVersion = errors.New("hook pin file written by a newer gridctl") ErrNotPinned = errors.New("hook is not pinned") ErrNotFound = errors.New("hook not found") ErrHashMismatch = errors.New("hook content changed since the reviewed diff") ErrReasonRequired = errors.New("approving a hook with unresolved findings requires a reason") )
Sentinel errors. Load's ErrCorrupt and ErrNewerVersion follow the skill pin contract: a corrupt file is reported and not rewritten; ErrNewerVersion must never be papered over.
Functions ¶
This section is empty.
Types ¶
type ApproveRequest ¶
type ApproveRequest struct {
ExpectedHash string
Reason string
Evidence []string
ApprovedBy string
ApprovedBySource string
// Findings are advisory results for the content being approved. When
// Scanned is true, Findings is the current scan, including an empty
// list that clears findings recorded on an earlier pin. When Scanned
// is false and Findings is empty, the stored findings are kept.
// A non-empty effective list requires Reason.
Findings []pins.Finding
Scanned bool
}
ApproveRequest is one explicit hook approval.
type HookDiff ¶
type HookDiff struct {
Name string `json:"name"`
OldHash string `json:"old_definition_hash"`
NewHash string `json:"new_definition_hash"`
OldDocument string `json:"old_document,omitempty"`
NewDocument string `json:"new_document,omitempty"`
AddedFiles []string `json:"added_files,omitempty"`
RemovedFiles []string `json:"removed_files,omitempty"`
ModifiedFiles []string `json:"modified_files,omitempty"`
Findings []pins.Finding `json:"findings,omitempty"`
}
HookDiff describes how a hook moved since its pin.
func (*HookDiff) DocumentChanged ¶
DocumentChanged reports whether hook.json moved.
type HookPin ¶
type HookPin struct {
// DefinitionHash is the SHA-256 of hook.json bytes.
DefinitionHash string `json:"definition_hash"`
// Files are per-file digests over every installed file except
// .origin.json, dot-prefixed entries, .tmp files, symlinks, and
// irregular files. Sorted by path.
Files []skillpins.FileDigest `json:"files,omitempty"`
// Document is the hook.json text as pinned, kept so drift review can
// show a diff.
Document string `json:"document,omitempty"`
Source string `json:"source,omitempty"`
Origin *skillpins.OriginRef `json:"origin,omitempty"`
ApprovedReason string `json:"approved_reason,omitempty"`
PinnedAt time.Time `json:"pinned_at"`
LastVerifiedAt time.Time `json:"last_verified_at"`
Status string `json:"status"`
Findings []pins.Finding `json:"findings,omitempty"`
Approvals []pinapprovals.Entry `json:"approvals,omitempty"`
CompositeHash string `json:"composite_hash,omitempty"`
}
HookPin is the pin record for one hook. Approvals is rebuilt from the approvals log on every load. CompositeHash is recomputed from the digests.
type PinFile ¶
PinFile is the top-level JSON structure stored at ~/.gridctl/pins/hooks/global.json. Hook pins are not stack-scoped. The subdirectory keeps this file disjoint from the tool pin file of a stack named hooks.
type PinRequest ¶
type PinRequest struct {
Name string
Dir string
Findings []pins.Finding
Origin *skillpins.OriginRef
Source string
}
PinRequest is the content an accepted import pins.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store manages TOFU content pins for hooks. Writes hold a file lock and are atomic. The store is not stack-scoped.
func New ¶
func New() *Store
New creates a Store for ~/.gridctl/pins/hooks/global.json. The path is resolved on first use so construction stays error-free.
func NewWithPath ¶
NewWithPath creates a Store that keeps pins in dir/hooks/global.json. Intended for tests; it never resolves the real home.
func (*Store) Approve ¶
Approve re-pins the hook's current bytes and appends an approval entry. The log is appended inside the file lock before the pin file is rewritten.
func (*Store) CurrentCompositeHash ¶
CurrentCompositeHash is the approval fingerprint of the hook's current bytes.
func (*Store) Diff ¶
func (s *Store) Diff(name, registryDir string) (*VerifyResult, error)
Diff is Verify's diff. A clean pin returns a diff with equal hashes and status pinned so callers can still print the composite hash.
func (*Store) Get ¶
Get returns a copy of one pin. The bool is false when the name is not pinned. Load must have succeeded.
func (*Store) Load ¶
Load reads the pin file. A missing file starts empty. A corrupt file resets to empty and wraps ErrCorrupt. A newer version resets to empty and wraps ErrNewerVersion with the skill-pin wording shape.
func (*Store) Pin ¶
func (s *Store) Pin(ctx context.Context, req PinRequest) error
Pin records the bytes currently installed in req.Dir. An accepted import calls this, including when the bytes changed. It does not append an approval entry.
type SyncResult ¶
SyncResult summarizes one verify pass over pinned hooks. Sync does not re-pin changed bytes; that happens only on an accepted import or approve.