Add WIMSE ECT reference implementation (Go)
- ect library: create, verify, DAG validation, ledger interface - In-memory ledger and ECTStore for full ledger mode - Test vectors and unit tests; two-agent demo (cmd/demo) - README: document refimpl scope and usage Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
97
refimpl/ect/types.go
Normal file
97
refimpl/ect/types.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Package ect implements Execution Context Tokens (ECTs) per
|
||||
// draft-nennemann-wimse-execution-context-00.
|
||||
package ect
|
||||
|
||||
import "time"
|
||||
|
||||
// ECTType is the JOSE typ value for ECTs.
|
||||
const ECTType = "wimse-exec+jwt"
|
||||
|
||||
// PolDecision values per Section 4.2.3.
|
||||
const (
|
||||
PolDecisionApproved = "approved"
|
||||
PolDecisionRejected = "rejected"
|
||||
PolDecisionPendingHumanReview = "pending_human_review"
|
||||
)
|
||||
|
||||
// Payload holds ECT JWT claims per Section 4.2.
|
||||
type Payload struct {
|
||||
// Standard JWT claims (required unless noted)
|
||||
Iss string `json:"iss"` // REQUIRED: issuer, SPIFFE ID
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Aud Audience `json:"aud"` // REQUIRED
|
||||
Iat int64 `json:"iat"` // REQUIRED: NumericDate
|
||||
Exp int64 `json:"exp"` // REQUIRED
|
||||
Jti string `json:"jti"` // REQUIRED: UUID
|
||||
|
||||
// Execution context (Section 4.2.2)
|
||||
Wid string `json:"wid,omitempty"` // OPTIONAL: workflow ID, UUID
|
||||
Tid string `json:"tid"` // REQUIRED: task ID, UUID
|
||||
ExecAct string `json:"exec_act"` // REQUIRED
|
||||
Par []string `json:"par"` // REQUIRED: parent task IDs
|
||||
|
||||
// Policy evaluation (Section 4.2.3)
|
||||
Pol string `json:"pol"` // REQUIRED
|
||||
PolDecision string `json:"pol_decision"` // REQUIRED: approved | rejected | pending_human_review
|
||||
PolEnforcer string `json:"pol_enforcer,omitempty"` // OPTIONAL
|
||||
PolTimestamp int64 `json:"pol_timestamp,omitempty"` // OPTIONAL
|
||||
|
||||
// Data integrity (Section 4.2.4)
|
||||
InpHash string `json:"inp_hash,omitempty"`
|
||||
OutHash string `json:"out_hash,omitempty"`
|
||||
InpClassification string `json:"inp_classification,omitempty"`
|
||||
|
||||
// Task metadata (Section 4.2.5)
|
||||
ExecTimeMs int `json:"exec_time_ms,omitempty"`
|
||||
RegulatedDomain string `json:"regulated_domain,omitempty"`
|
||||
ModelVersion string `json:"model_version,omitempty"`
|
||||
WitnessedBy []string `json:"witnessed_by,omitempty"`
|
||||
|
||||
// Compensation (Section 4.2.6)
|
||||
CompensationRequired bool `json:"compensation_required,omitempty"`
|
||||
CompensationReason string `json:"compensation_reason,omitempty"`
|
||||
|
||||
// Extensions (Section 4.2.7)
|
||||
Ext map[string]interface{} `json:"ext,omitempty"`
|
||||
}
|
||||
|
||||
// Audience is aud claim: string or array of strings.
|
||||
type Audience []string
|
||||
|
||||
// MarshalJSON encodes aud as single string if one element, else array.
|
||||
func (a Audience) MarshalJSON() ([]byte, error) {
|
||||
if len(a) == 1 {
|
||||
return marshalJSONString(a[0]), nil
|
||||
}
|
||||
return marshalJSONStringArray(a), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes aud from string or array.
|
||||
func (a *Audience) UnmarshalJSON(data []byte) error {
|
||||
return unmarshalAudience(data, a)
|
||||
}
|
||||
|
||||
// ValidPolDecision returns true if s is a registered pol_decision value.
|
||||
func ValidPolDecision(s string) bool {
|
||||
return s == PolDecisionApproved || s == PolDecisionRejected || s == PolDecisionPendingHumanReview
|
||||
}
|
||||
|
||||
// ContainsAudience returns true if verifierID is in the audience.
|
||||
func (p *Payload) ContainsAudience(verifierID string) bool {
|
||||
for _, id := range p.Aud {
|
||||
if id == verifierID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IATTime returns p.Iat as time.Time.
|
||||
func (p *Payload) IATTime() time.Time {
|
||||
return time.Unix(p.Iat, 0)
|
||||
}
|
||||
|
||||
// ExpTime returns p.Exp as time.Time.
|
||||
func (p *Payload) ExpTime() time.Time {
|
||||
return time.Unix(p.Exp, 0)
|
||||
}
|
||||
Reference in New Issue
Block a user