- Rename `par` to `pred` (predecessor) in types, serialization, tests - Remove `pol`, `pol_decision` from core payload; move to `ect_ext` - Remove `sub` from payload (not part of ECT spec) - Update `typ` from `wimse-exec+jwt` to `exec+jwt` (accept both) - Rename MaxParLength to MaxPredLength everywhere - Update testdata, demos, READMEs with migration table - All Go tests pass, all 56 Python tests pass (90% coverage)
126 lines
3.5 KiB
Go
126 lines
3.5 KiB
Go
// Demo runs a minimal two-agent ECT workflow: Agent A creates a root ECT,
|
|
// "sends" it to Agent B; Agent B verifies, appends to ledger, then creates
|
|
// a child ECT; verification runs with DAG validation against the ledger.
|
|
package main
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/nennemann/ect-refimpl/go-lang/ect"
|
|
)
|
|
|
|
func main() {
|
|
ledger := ect.NewMemoryLedger()
|
|
now := time.Now()
|
|
|
|
// Agent A: spec reviewer
|
|
keyA, err := ect.GenerateKey()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
agentA := "spiffe://example.com/agent/spec-reviewer"
|
|
agentB := "spiffe://example.com/agent/implementer"
|
|
kidA := "agent-a-key"
|
|
|
|
// 1) Agent A creates root ECT (task id = jti per spec)
|
|
payloadA := &ect.Payload{
|
|
Iss: agentA,
|
|
Aud: []string{agentB},
|
|
Iat: now.Unix(),
|
|
Exp: now.Add(10 * time.Minute).Unix(),
|
|
Jti: "550e8400-e29b-41d4-a716-446655440001",
|
|
Wid: "wf-demo-001",
|
|
ExecAct: "review_requirements_spec",
|
|
Pred: []string{},
|
|
Ext: map[string]interface{}{
|
|
"pol": "spec_review_policy_v2",
|
|
"pol_decision": "approved",
|
|
},
|
|
}
|
|
ectA, err := ect.Create(payloadA, keyA, ect.CreateOptions{KeyID: kidA})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println("Agent A created root ECT (jti=550e8400-..., review_requirements_spec)")
|
|
|
|
// 2) Agent B verifies (no store for DAG on first ECT)
|
|
resolveKey := func(kid string) (*ecdsa.PublicKey, error) {
|
|
if kid == kidA {
|
|
return &keyA.PublicKey, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
opts := ect.VerifyOptions{
|
|
VerifierID: agentB,
|
|
ResolveKey: resolveKey,
|
|
Store: ledger,
|
|
Now: now,
|
|
IATMaxAge: 15 * time.Minute,
|
|
IATMaxFuture: 30 * time.Second,
|
|
}
|
|
parsed, err := ect.Verify(ectA, opts)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
_, err = ledger.Append(ectA, parsed.Payload)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println("Agent B verified root ECT and appended to ledger")
|
|
|
|
// 3) Agent B creates child ECT (pred contains predecessor jti values per spec)
|
|
keyB, _ := ect.GenerateKey()
|
|
kidB := "agent-b-key"
|
|
payloadB := &ect.Payload{
|
|
Iss: agentB,
|
|
Aud: []string{"spiffe://example.com/system/ledger"},
|
|
Iat: now.Unix() + 1,
|
|
Exp: now.Add(10 * time.Minute).Unix(),
|
|
Jti: "550e8400-e29b-41d4-a716-446655440002",
|
|
Wid: "wf-demo-001",
|
|
ExecAct: "implement_module",
|
|
Pred: []string{"550e8400-e29b-41d4-a716-446655440001"},
|
|
Ext: map[string]interface{}{
|
|
"pol": "coding_standards_v3",
|
|
"pol_decision": "approved",
|
|
},
|
|
}
|
|
ectB, err := ect.Create(payloadB, keyB, ect.CreateOptions{KeyID: kidB})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println("Agent B created child ECT (jti=550e8400-...002, implement_module, pred=[predecessor jti])")
|
|
|
|
// 4) Verify child ECT with DAG (ledger has task-001)
|
|
resolverB := ect.KeyResolver(func(kid string) (*ecdsa.PublicKey, error) {
|
|
if kid == kidB {
|
|
return &keyB.PublicKey, nil
|
|
}
|
|
if kid == kidA {
|
|
return &keyA.PublicKey, nil
|
|
}
|
|
return nil, nil
|
|
})
|
|
optsB := ect.VerifyOptions{
|
|
VerifierID: "spiffe://example.com/system/ledger",
|
|
ResolveKey: resolverB,
|
|
Store: ledger,
|
|
Now: now.Add(2 * time.Second),
|
|
IATMaxAge: 15 * time.Minute,
|
|
IATMaxFuture: 30 * time.Second,
|
|
}
|
|
parsedB, err := ect.Verify(ectB, optsB)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
_, err = ledger.Append(ectB, parsedB.Payload)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println("Verified child ECT with DAG validation and appended to ledger")
|
|
fmt.Printf("Ledger entries: %s (%s), %s (%s)\n", parsed.Payload.Jti, parsed.Payload.ExecAct, parsedB.Payload.Jti, parsedB.Payload.ExecAct)
|
|
}
|