-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproof.go
More file actions
296 lines (253 loc) · 7.72 KB
/
proof.go
File metadata and controls
296 lines (253 loc) · 7.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
package proof
import (
"encoding/json"
"fmt"
"os"
"time"
"github.com/Clyra-AI/proof/core/bundle"
"github.com/Clyra-AI/proof/core/canon"
"github.com/Clyra-AI/proof/core/chain"
"github.com/Clyra-AI/proof/core/framework"
"github.com/Clyra-AI/proof/core/record"
"github.com/Clyra-AI/proof/core/schema"
"github.com/Clyra-AI/proof/core/signing"
)
type Record = record.Record
type RecordOpts = record.RecordOpts
type Controls = record.Controls
type Relationship = record.Relationship
type Relations = record.Relations
type RelationshipRef = record.RelationshipRef
type RelationshipEdge = record.RelationshipEdge
type AgentChainHop = record.AgentChainHop
type PolicyRef = record.PolicyRef
type AgentLineageHop = record.AgentLineageHop
type Chain = chain.Chain
type ChainVerification = chain.Verification
type SigningKey = signing.SigningKey
type PublicKey = signing.PublicKey
type Signature = signing.Signature
type RevocationList = signing.RevocationList
type RevocationEntry = signing.RevocationEntry
type CosignVerifyOpts = signing.CosignVerifyOpts
type Framework = framework.Framework
type RecordType = schema.RecordType
type CanonDomain = canon.Domain
type Digest = canon.Digest
type BundleManifestEntry = bundle.ManifestEntry
type BundleManifest = bundle.Manifest
type BundleVerifyOpts = bundle.VerifyOpts
const (
DomainJSON = canon.DomainJSON
DomainSQL = canon.DomainSQL
DomainURL = canon.DomainURL
DomainText = canon.DomainText
DomainPrompt = canon.DomainPrompt
)
func NewRecord(opts RecordOpts) (*Record, error) {
r, err := record.New(opts)
if err != nil {
return nil, err
}
if err := ValidateRecord(r); err != nil {
return nil, err
}
return r, nil
}
func Sign(r *Record, key SigningKey) (*Record, error) {
return signing.Sign(r, key)
}
func Verify(r *Record, publicKey PublicKey) error {
return signing.Verify(r, publicKey)
}
func AppendToChain(c *Chain, r *Record) error {
return chain.Append(c, r)
}
func VerifyChain(c *Chain) (*ChainVerification, error) {
return chain.Verify(c)
}
func Canonicalize(input []byte, domain CanonDomain) ([]byte, error) {
return canon.Canonicalize(input, domain)
}
func DigestValue(input []byte, domain CanonDomain, saltID string) (Digest, error) {
return canon.DigestInfo(input, domain, saltID)
}
func DigestHMACValue(input []byte, domain CanonDomain, secret []byte, saltID string) (Digest, error) {
return canon.DigestHMACInfo(input, domain, secret, saltID)
}
func LoadFramework(pathOrID string) (*Framework, error) {
return framework.Load(pathOrID)
}
func ListRecordTypes() []RecordType {
return schema.ListRecordTypes()
}
func ValidateRecord(r *Record) error {
if err := record.Validate(r); err != nil {
return err
}
raw, err := json.Marshal(r)
if err != nil {
return err
}
return schema.ValidateRecord(raw, r.RecordType)
}
func ComputeRecordHash(r *Record) (string, error) {
return record.ComputeHash(r)
}
func NewChain(id string) *Chain {
return chain.New(id, time.Now().UTC())
}
func VerifyChainRange(c *Chain, from, to time.Time) (*ChainVerification, error) {
return chain.VerifyRange(c, from, to)
}
func GenerateSigningKey() (SigningKey, error) {
return signing.GenerateKey()
}
func WriteRecord(path string, r *Record) error {
raw, err := json.MarshalIndent(r, "", " ")
if err != nil {
return err
}
// #nosec G306 -- proof artifacts are intentionally shareable within local workspace.
return os.WriteFile(path, raw, 0o644)
}
func ReadRecord(path string) (*Record, error) {
// #nosec G304 -- library API reads explicit caller-provided artifact paths.
raw, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var r Record
if err := json.Unmarshal(raw, &r); err != nil {
return nil, err
}
return &r, nil
}
func ReadAndValidateRecord(path string) (*Record, error) {
r, err := ReadRecord(path)
if err != nil {
return nil, err
}
if err := ValidateRecord(r); err != nil {
return nil, err
}
return r, nil
}
func ValidateCustomTypeSchema(schemaPath string) error {
// #nosec G304 -- schema path is explicit user input for validation.
raw, err := os.ReadFile(schemaPath)
if err != nil {
return err
}
if err := schema.ValidateCustomSchema(schemaPath, raw); err != nil {
return fmt.Errorf("invalid schema: %w", err)
}
return nil
}
func RegisterCustomType(recordType string, schemaJSON []byte) error {
return schema.RegisterCustomType(recordType, "<inline>", schemaJSON)
}
func RegisterCustomTypeSchema(recordType, schemaPath string) error {
// #nosec G304 -- schema path is explicit user input for validation.
raw, err := os.ReadFile(schemaPath)
if err != nil {
return err
}
return schema.RegisterCustomType(recordType, schemaPath, raw)
}
func ResetCustomTypes() {
schema.ResetCustomTypes()
}
func SignChain(c *Chain, key SigningKey) (Signature, error) {
if c == nil {
return Signature{}, fmt.Errorf("chain is nil")
}
digest, err := chainDigest(c)
if err != nil {
return Signature{}, err
}
sig, err := signing.SignDigest(digest, key)
if err != nil {
return Signature{}, err
}
c.Signatures = append(c.Signatures, sig)
return sig, nil
}
func VerifyChainSignature(c *Chain, sig Signature, pub PublicKey) error {
if c == nil {
return fmt.Errorf("chain is nil")
}
digest, err := chainDigest(c)
if err != nil {
return err
}
return signing.VerifyDigest(sig, digest, pub)
}
func SignRevocationList(list RevocationList, key SigningKey) (RevocationList, error) {
return signing.SignRevocationList(list, key)
}
func VerifyRevocationList(list RevocationList, pub PublicKey) error {
return signing.VerifyRevocationList(list, pub)
}
func IsKeyRevoked(list RevocationList, keyID string, at time.Time) bool {
return signing.IsRevoked(list, keyID, at)
}
func SignCosign(r *Record, keyPath string) (*Record, error) {
return signing.SignRecordCosign(r, keyPath)
}
func VerifyCosign(r *Record, keyPath string) error {
return signing.VerifyRecordCosign(r, signing.CosignVerifyOpts{KeyPath: keyPath})
}
func VerifyCosignWithOptions(r *Record, opts CosignVerifyOpts) error {
return signing.VerifyRecordCosign(r, opts)
}
func IsDependencyMissing(err error) bool {
return signing.IsDependencyMissing(err)
}
func VerifyBundle(path string, opts BundleVerifyOpts) (*BundleManifest, error) {
return bundle.Verify(path, opts)
}
func SignBundleManifest(manifest BundleManifest, key SigningKey) (*BundleManifest, error) {
signed, err := bundle.SignManifest(manifest, key)
if err != nil {
return nil, err
}
return &signed, nil
}
func SignBundleManifestCosign(manifest BundleManifest, keyPath string) (*BundleManifest, error) {
signed, err := bundle.SignManifestCosign(manifest, keyPath)
if err != nil {
return nil, err
}
return &signed, nil
}
func SignBundleFile(path string, key SigningKey) (*BundleManifest, error) {
return bundle.SignFile(path, key)
}
func SignBundleCosignFile(path string, keyPath string) (*BundleManifest, error) {
return bundle.SignFileCosign(path, keyPath)
}
// Deprecated: SignBundle mutates <path>/manifest.json.
// Use SignBundleManifest for pure signing or SignBundleFile for explicit file mutation.
func SignBundle(path string, key SigningKey) (*BundleManifest, error) {
return SignBundleFile(path, key)
}
// Deprecated: SignBundleCosign mutates <path>/manifest.json.
// Use SignBundleManifestCosign for pure signing or SignBundleCosignFile for explicit file mutation.
func SignBundleCosign(path string, keyPath string) (*BundleManifest, error) {
return SignBundleCosignFile(path, keyPath)
}
func chainDigest(c *Chain) (string, error) {
payload := map[string]any{
"chain_id": c.ChainID,
"created_at": c.CreatedAt.UTC().Format(time.RFC3339),
"record_count": c.RecordCount,
"head_hash": c.HeadHash,
"records": c.Records,
}
raw, err := json.Marshal(payload)
if err != nil {
return "", err
}
return canon.DigestHex(raw, canon.DomainJSON)
}