Files
ietf-wimse-ect/refimpl/go-lang/cmd/demo/main.go
Christian Nennemann bbf557e54b Restructure refimpl into go-lang and python subdirectories
Move Go reference implementation to refimpl/go-lang/ and add new
Python reference implementation in refimpl/python/. Update build.sh
with renamed draft and simplified tool paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:11:55 +01:00

122 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",
Par: []string{},
Pol: "spec_review_policy_v2",
PolDecision: ect.PolDecisionApproved,
}
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 (par contains parent 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",
Par: []string{"550e8400-e29b-41d4-a716-446655440001"},
Pol: "coding_standards_v3",
PolDecision: ect.PolDecisionApproved,
}
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, par=[parent 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)
}