@@ -10,11 +10,13 @@ import (
1010 "path/filepath"
1111 "strings"
1212
13+ "github.com/github/go-spdx/v2/spdxexp"
1314 "gopkg.in/yaml.v3"
1415
15- "github.com/github/go-spdx/v2/spdxexp"
16+ beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"
17+ "github.com/oasisprotocol/oasis-core/go/common/sgx"
18+ "github.com/oasisprotocol/oasis-core/go/common/sgx/quote"
1619 "github.com/oasisprotocol/oasis-core/go/common/version"
17-
1820 "github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl"
1921)
2022
@@ -264,7 +266,7 @@ type Deployment struct {
264266 // TrustRoot is the optional trust root configuration.
265267 TrustRoot * TrustRootConfig `yaml:"trust_root,omitempty" json:"trust_root,omitempty"`
266268 // Policy is the ROFL app policy.
267- Policy * rofl. AppAuthPolicy `yaml:"policy,omitempty" json:"policy,omitempty"`
269+ Policy * AppAuthPolicy `yaml:"policy,omitempty" json:"policy,omitempty"`
268270 // Metadata contains custom metadata.
269271 Metadata map [string ]string `yaml:"metadata,omitempty" json:"metadata,omitempty"`
270272 // Secrets contains encrypted secrets.
@@ -288,6 +290,12 @@ func (d *Deployment) Validate() error {
288290 if d .ParaTime == "" {
289291 return fmt .Errorf ("paratime cannot be empty" )
290292 }
293+ if d .Policy != nil {
294+ err := d .Policy .Validate ()
295+ if err != nil {
296+ return fmt .Errorf ("bad app policy: %w" , err )
297+ }
298+ }
291299 for _ , s := range d .Secrets {
292300 if err := s .Validate (); err != nil {
293301 return fmt .Errorf ("bad secret: %w" , err )
@@ -307,6 +315,91 @@ func (d *Deployment) HasAppID() bool {
307315 return len (d .AppID ) > 0
308316}
309317
318+ // AppAuthPolicy is the per-application ROFL policy.
319+ //
320+ // This is a different type from `rofl.AppAuthPolicy` in order to add extra structure that makes it
321+ // easier to configure without changing the on-chain representation.
322+ type AppAuthPolicy struct {
323+ // Quotes is a quote policy.
324+ Quotes quote.Policy `json:"quotes" yaml:"quotes"`
325+ // Enclaves is the set of allowed enclave identities.
326+ Enclaves []* EnclaveIdentity `json:"enclaves" yaml:"enclaves"`
327+ // Endorsements is the set of allowed endorsements.
328+ Endorsements []rofl.AllowedEndorsement `json:"endorsements" yaml:"endorsements"`
329+ // Fees is the gas fee payment policy.
330+ Fees rofl.FeePolicy `json:"fees" yaml:"fees"`
331+ // MaxExpiration is the maximum number of future epochs for which one can register.
332+ MaxExpiration beacon.EpochTime `json:"max_expiration" yaml:"max_expiration"`
333+ }
334+
335+ // Validate validates the policy for correctness.
336+ func (p * AppAuthPolicy ) Validate () error {
337+ for idx , ei := range p .Enclaves {
338+ if err := ei .Validate (); err != nil {
339+ return fmt .Errorf ("bad enclave identity %d: %w" , idx , err )
340+ }
341+ }
342+ return nil
343+ }
344+
345+ // AsDescriptor converts the structure into an on-chain policy descriptor.
346+ func (p * AppAuthPolicy ) AsDescriptor () * rofl.AppAuthPolicy {
347+ enclaves := make ([]sgx.EnclaveIdentity , 0 , len (p .Enclaves ))
348+ for _ , ei := range p .Enclaves {
349+ enclaves = append (enclaves , ei .ID )
350+ }
351+
352+ return & rofl.AppAuthPolicy {
353+ Quotes : p .Quotes ,
354+ Enclaves : enclaves ,
355+ Endorsements : p .Endorsements ,
356+ Fees : p .Fees ,
357+ MaxExpiration : p .MaxExpiration ,
358+ }
359+ }
360+
361+ // EnclaveIdentity is the cryptographic enclave identity.
362+ type EnclaveIdentity struct {
363+ // ID is the enclave identity.
364+ ID sgx.EnclaveIdentity `json:"id" yaml:"id"`
365+ // Version is an optional version this enclave identity is for, with an empty value indicating
366+ // the latest version.
367+ //
368+ // This can be used to keep historic versions in the current policy.
369+ Version string `json:"version,omitempty" yaml:"version,omitempty"`
370+ // Description is an optional description of an enclave identity.
371+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
372+ }
373+
374+ // UnmarshalYAML implements yaml.Unmarshaler.
375+ func (ei * EnclaveIdentity ) UnmarshalYAML (value * yaml.Node ) error {
376+ switch value .ShortTag () {
377+ case "!!str" :
378+ // Simple mode with just the enclave identity and no other information.
379+ ei .Description = ""
380+ ei .Version = ""
381+ return value .Decode (& ei .ID )
382+ default :
383+ type enclaveIdentity EnclaveIdentity
384+ return value .Decode ((* enclaveIdentity )(ei ))
385+ }
386+ }
387+
388+ // Validate validates the enclave identity for correctness.
389+ func (ei * EnclaveIdentity ) Validate () error {
390+ if len (ei .Version ) > 0 {
391+ if _ , err := version .FromString (ei .Version ); err != nil {
392+ return fmt .Errorf ("malformed version: %w" , err )
393+ }
394+ }
395+ return nil
396+ }
397+
398+ // IsLatest returns true iff the enclave identity is for the latest app version.
399+ func (ei * EnclaveIdentity ) IsLatest () bool {
400+ return ei .Version == ""
401+ }
402+
310403// Machine is a hosted machine where a ROFL app is deployed.
311404type Machine struct {
312405 // Provider is the address of the ROFL market provider to deploy to.
0 commit comments