stemedb/sdk/go/steme/aphoria.go
jordan 1cc453c97b feat: Aphoria policy source tracking + claim extraction pipeline
- Add PolicySourceStore for tracking where policies come from
- Implement claim extraction skill and API endpoints
- Add community UI text selection extractor component
- Create Go SDK aphoria client for policy operations
- Document patent specifications and legal disclosures
- Add guides: golden path loop, policy audit trails, pre-flight checks
- Expand Unreal Engine config extractor with source tracking
- Add UAT reports for policy source tracking validation
- Refactor tests.rs into modular test files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 02:35:02 -07:00

350 lines
10 KiB
Go

package steme
import (
"context"
"fmt"
)
// AphoriaClient provides access to Aphoria code-level truth linting endpoints.
//
// Aphoria scans codebases, extracts decisions embedded in config and code,
// and checks them against authoritative sources (RFCs, OWASP, etc.).
type AphoriaClient struct {
client *Client
}
// Aphoria returns a client for Aphoria operations.
//
// Example:
//
// result, err := client.Aphoria().Scan(ctx, ScanParams{
// TargetPath: "/path/to/project",
// })
func (c *Client) Aphoria() *AphoriaClient {
return &AphoriaClient{client: c}
}
// BlessParams defines parameters for blessing a code pattern.
type BlessParams struct {
// ConceptPath to bless (e.g., "code://rust/grpc/tls").
ConceptPath string `json:"concept_path"`
// Predicate being defined (e.g., "enabled", "min_version").
Predicate string `json:"predicate"`
// Value for this standard (e.g., "true", "1.2").
Value string `json:"value"`
// Reason/description for why this is the standard.
Reason string `json:"reason"`
}
// BlessResult represents the response from blessing a pattern.
type BlessResult struct {
Success bool `json:"success"`
Message string `json:"message"`
ConceptPath string `json:"concept_path"`
}
// Bless marks a code pattern as the authoritative standard.
//
// Unlike acknowledge (which creates a suppression), bless creates an
// assertion with the actual predicate and value that becomes the
// authoritative standard for future scans.
//
// Example:
//
// result, err := client.Aphoria().Bless(ctx, BlessParams{
// ConceptPath: "code://rust/grpc/tls",
// Predicate: "enabled",
// Value: "true",
// Reason: "All services MUST use mTLS",
// })
func (a *AphoriaClient) Bless(ctx context.Context, params BlessParams) (*BlessResult, error) {
var result BlessResult
if err := a.client.doJSON(ctx, "POST", "/v1/aphoria/bless", params, &result); err != nil {
return nil, err
}
return &result, nil
}
// ExportPolicyParams defines parameters for exporting a Trust Pack.
type ExportPolicyParams struct {
// Name for the Trust Pack (e.g., "acme-security-policy").
Name string `json:"name"`
// Description for the pack (optional).
Description string `json:"description,omitempty"`
// OutputPath where the pack should be saved (optional).
// If not provided, uses default name based on pack name.
OutputPath string `json:"output_path,omitempty"`
}
// ExportPolicyResult represents the response from exporting a policy.
type ExportPolicyResult struct {
// PackPath where the pack was saved.
PackPath string `json:"pack_path,omitempty"`
// Number of assertions exported.
AssertionsCount int `json:"assertions_count"`
// Number of aliases exported.
AliasesCount int `json:"aliases_count"`
// Hex-encoded issuer public key (first 8 chars).
IssuerHex string `json:"issuer_hex"`
// Name of the exported pack.
PackName string `json:"pack_name"`
// Version of the exported pack.
PackVersion string `json:"pack_version"`
}
// ExportPolicy exports policy assertions as a Trust Pack.
//
// Collects all acknowledged conflicts and manual aliases into a signed
// Trust Pack that can be shared with other projects.
//
// Example:
//
// result, err := client.Aphoria().ExportPolicy(ctx, ExportPolicyParams{
// Name: "acme-security",
// Description: "Acme Corp security standards",
// OutputPath: "./acme-security.pack",
// })
func (a *AphoriaClient) ExportPolicy(ctx context.Context, params ExportPolicyParams) (*ExportPolicyResult, error) {
var result ExportPolicyResult
if err := a.client.doJSON(ctx, "POST", "/v1/aphoria/policy/export", params, &result); err != nil {
return nil, err
}
return &result, nil
}
// ImportPolicyParams defines parameters for importing a Trust Pack.
type ImportPolicyParams struct {
// PackPath to the Trust Pack file.
PackPath string `json:"pack_path"`
}
// ImportPolicyResult represents the response from importing a policy.
type ImportPolicyResult struct {
Success bool `json:"success"`
// Number of assertions imported.
AssertionsImported int `json:"assertions_imported"`
// Number of aliases imported.
AliasesImported int `json:"aliases_imported"`
// Name of the imported pack.
PackName string `json:"pack_name"`
// Version of the imported pack.
PackVersion string `json:"pack_version"`
// Hex-encoded issuer public key (first 8 chars).
IssuerHex string `json:"issuer_hex"`
}
// ImportPolicy imports a Trust Pack into the local Episteme.
//
// Loads and verifies the pack's signature, then imports assertions
// and aliases into the local storage.
//
// Example:
//
// result, err := client.Aphoria().ImportPolicy(ctx, ImportPolicyParams{
// PackPath: "./acme-security.pack",
// })
func (a *AphoriaClient) ImportPolicy(ctx context.Context, params ImportPolicyParams) (*ImportPolicyResult, error) {
var result ImportPolicyResult
if err := a.client.doJSON(ctx, "POST", "/v1/aphoria/policy/import", params, &result); err != nil {
return nil, err
}
return &result, nil
}
// ScanParams defines parameters for scanning a project.
type ScanParams struct {
// TargetPath to the project root to scan.
TargetPath string `json:"target_path"`
// Format for output: "table", "json", "sarif", "markdown".
// Defaults to "json".
Format string `json:"format,omitempty"`
// FailOnFlag returns 422 status code if BLOCK findings exist.
FailOnFlag bool `json:"fail_on_flag,omitempty"`
// MinSeverity to report: "pass", "flag", "block".
MinSeverity string `json:"min_severity,omitempty"`
// Debug enables conflict resolution traces in the output.
Debug bool `json:"debug,omitempty"`
}
// ScanResult represents the response from a scan operation.
type ScanResult struct {
// Project name.
Project string `json:"project"`
// Unique scan ID.
ScanID string `json:"scan_id"`
// Number of files scanned.
FilesScanned int `json:"files_scanned"`
// Number of claims extracted.
ClaimsExtracted int `json:"claims_extracted"`
// Findings (conflicts detected).
Findings []Finding `json:"findings"`
// Summary counts by verdict.
Summary ScanSummary `json:"summary"`
}
// HasBlocks returns true if any findings have BLOCK verdict.
func (r *ScanResult) HasBlocks() bool {
return r.Summary.Blocked > 0
}
// HasFlags returns true if any findings have FLAG verdict.
func (r *ScanResult) HasFlags() bool {
return r.Summary.Flagged > 0
}
// Finding represents a single finding from the scan.
type Finding struct {
// ConceptPath of the claim.
ConceptPath string `json:"concept_path"`
// Predicate being claimed.
Predicate string `json:"predicate"`
// Value found in code.
CodeValue string `json:"code_value"`
// Source file path.
File string `json:"file"`
// Line number in the source file.
Line int `json:"line"`
// ConflictScore (0.0 to 1.0).
ConflictScore float64 `json:"conflict_score"`
// Verdict: "BLOCK", "FLAG", "PASS", "ACK".
Verdict string `json:"verdict"`
// Conflicts with authoritative sources.
Conflicts []ConflictingSource `json:"conflicts"`
// Acknowledgment info if this conflict was acknowledged.
Acknowledgment *Acknowledgment `json:"acknowledgment,omitempty"`
// Debug trace (if debug mode enabled).
Trace *ConflictTrace `json:"trace,omitempty"`
}
// IsBlocked returns true if this finding has BLOCK verdict.
func (f *Finding) IsBlocked() bool {
return f.Verdict == "BLOCK"
}
// IsFlagged returns true if this finding has FLAG verdict.
func (f *Finding) IsFlagged() bool {
return f.Verdict == "FLAG"
}
// ConflictingSource represents a source that conflicts with a code claim.
type ConflictingSource struct {
// Path of the authoritative source.
Path string `json:"path"`
// SourceClass (tier name).
SourceClass string `json:"source_class"`
// Authoritative value.
Value string `json:"value"`
// RFC/OWASP citation if applicable.
Citation string `json:"citation,omitempty"`
// PolicySource info if from a Trust Pack.
PolicySource *PolicySource `json:"policy_source,omitempty"`
}
// PolicySource contains information about a Trust Pack.
type PolicySource struct {
PackName string `json:"pack_name"`
PackVersion string `json:"pack_version"`
IssuerHex string `json:"issuer_hex"`
}
// Acknowledgment contains information about a conflict acknowledgment.
type Acknowledgment struct {
Timestamp string `json:"timestamp"`
By string `json:"by"`
Reason string `json:"reason"`
}
// ConflictTrace contains debug information about conflict resolution.
type ConflictTrace struct {
CodeClaim string `json:"code_claim"`
AuthorityMatch string `json:"authority_match"`
AuthorityTier string `json:"authority_tier"`
Resolution string `json:"resolution"`
}
// ScanSummary contains counts by verdict.
type ScanSummary struct {
Total int `json:"total"`
Blocked int `json:"blocked"`
Flagged int `json:"flagged"`
Passed int `json:"passed"`
Acknowledged int `json:"acknowledged"`
}
// Scan runs a scan on a project for conflicts.
//
// Scans the specified project directory, extracts claims from code/config,
// and checks them against authoritative sources.
//
// When FailOnFlag is true and BLOCK findings exist, the API returns 422
// and this method returns an APIError with StatusCode 422. The result
// is still accessible via the error.
//
// Example:
//
// result, err := client.Aphoria().Scan(ctx, ScanParams{
// TargetPath: "/path/to/project",
// Format: "json",
// FailOnFlag: true,
// })
// if err != nil {
// if apiErr, ok := err.(*APIError); ok && apiErr.StatusCode == 422 {
// // Scan succeeded but found blocking issues
// fmt.Printf("Found %d blocking issues\n", result.Summary.Blocked)
// }
// }
func (a *AphoriaClient) Scan(ctx context.Context, params ScanParams) (*ScanResult, error) {
if params.Format == "" {
params.Format = "json"
}
var result ScanResult
if err := a.client.doJSON(ctx, "POST", "/v1/aphoria/scan", params, &result); err != nil {
// For 422, we still want to return the result if possible
if apiErr, ok := err.(*APIError); ok && apiErr.StatusCode == 422 {
// The response body may contain the scan result
return &result, fmt.Errorf("scan found blocking issues: %w", err)
}
return nil, err
}
return &result, nil
}