Skip to content

Commit 30afeba

Browse files
authored
Merge pull request #448 from oasisprotocol/kostko/feature/rofl-manifest-historic-eid
feat(cmd/rofl): Add historic enclave identity support
2 parents b09dcd2 + 1aa68e9 commit 30afeba

4 files changed

Lines changed: 128 additions & 23 deletions

File tree

build/rofl/manifest.go

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
311404
type Machine struct {
312405
// Provider is the address of the ROFL market provider to deploy to.

cmd/rofl/build/build.go

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"maps"
88
"os"
9+
"slices"
910

1011
"github.com/spf13/cobra"
1112
flag "github.com/spf13/pflag"
@@ -177,16 +178,20 @@ var (
177178
buildEnclaves[id.Enclave] = struct{}{}
178179
}
179180

180-
manifestEnclaves := make(map[sgx.EnclaveIdentity]struct{})
181+
allManifestEnclaves := make(map[sgx.EnclaveIdentity]struct{})
182+
latestManifestEnclaves := make(map[sgx.EnclaveIdentity]struct{})
181183
for _, eid := range deployment.Policy.Enclaves {
182-
manifestEnclaves[eid] = struct{}{}
184+
if eid.IsLatest() {
185+
latestManifestEnclaves[eid.ID] = struct{}{}
186+
}
187+
allManifestEnclaves[eid.ID] = struct{}{}
183188
}
184189

185190
// Perform verification when requested.
186191
if doVerify {
187-
showIdentityDiff := func(build, other map[sgx.EnclaveIdentity]struct{}, otherName string) {
188-
fmt.Println("Built enclave identities:")
189-
for enclaveID := range build {
192+
showIdentityDiff := func(this, other map[sgx.EnclaveIdentity]struct{}, thisName, otherName string) {
193+
fmt.Printf("%s enclave identities:\n", thisName)
194+
for enclaveID := range this {
190195
data, _ := enclaveID.MarshalText()
191196
fmt.Printf(" - %s\n", string(data))
192197
}
@@ -198,13 +203,16 @@ var (
198203
}
199204
}
200205

201-
if !maps.Equal(buildEnclaves, manifestEnclaves) {
202-
fmt.Println("Built enclave identities DIFFER from manifest enclave identities!")
203-
showIdentityDiff(buildEnclaves, manifestEnclaves, "Manifest")
206+
if !maps.Equal(buildEnclaves, latestManifestEnclaves) {
207+
fmt.Println("Built enclave identities DIFFER from latest manifest enclave identities!")
208+
showIdentityDiff(buildEnclaves, latestManifestEnclaves, "Built", "Manifest")
204209
cobra.CheckErr(fmt.Errorf("enclave identity verification failed"))
205210
}
206211

207-
fmt.Println("Built enclave identities MATCH manifest enclave identities.")
212+
fmt.Println("Built enclave identities MATCH latest manifest enclave identities.")
213+
if len(latestManifestEnclaves) != len(allManifestEnclaves) {
214+
fmt.Println("NOTE: Non-latest enclave identities present in manifest!")
215+
}
208216

209217
// When not in offline mode, also verify on-chain enclave identities.
210218
if !offline {
@@ -213,13 +221,13 @@ var (
213221
cfgEnclaves, err = roflCommon.GetRegisteredEnclaves(ctx, deployment.AppID, npa)
214222
cobra.CheckErr(err)
215223

216-
if !maps.Equal(buildEnclaves, cfgEnclaves) {
217-
fmt.Println("Built enclave identities DIFFER from on-chain enclave identities!")
218-
showIdentityDiff(buildEnclaves, cfgEnclaves, "On-chain")
224+
if !maps.Equal(allManifestEnclaves, cfgEnclaves) {
225+
fmt.Println("Manifest enclave identities DIFFER from on-chain enclave identities!")
226+
showIdentityDiff(allManifestEnclaves, cfgEnclaves, "Manifest", "On-chain")
219227
cobra.CheckErr(fmt.Errorf("enclave identity verification failed"))
220228
}
221229

222-
fmt.Println("Built enclave identities MATCH on-chain enclave identities.")
230+
fmt.Println("Manifest enclave identities MATCH on-chain enclave identities.")
223231
}
224232
return
225233
}
@@ -232,7 +240,7 @@ var (
232240
switch noUpdate {
233241
case true:
234242
// Ask the user to update the manifest manually (if the manifest has changed).
235-
if maps.Equal(buildEnclaves, manifestEnclaves) {
243+
if maps.Equal(buildEnclaves, latestManifestEnclaves) {
236244
fmt.Println("Built enclave identities already match manifest enclave identities.")
237245
break
238246
}
@@ -249,9 +257,13 @@ var (
249257
}
250258
case false:
251259
// Update the manifest with the given enclave identities, overwriting existing ones.
252-
deployment.Policy.Enclaves = make([]sgx.EnclaveIdentity, 0, len(ids))
260+
deployment.Policy.Enclaves = slices.DeleteFunc(deployment.Policy.Enclaves, func(ei *buildRofl.EnclaveIdentity) bool {
261+
return ei.IsLatest()
262+
})
253263
for _, id := range ids {
254-
deployment.Policy.Enclaves = append(deployment.Policy.Enclaves, id.Enclave)
264+
deployment.Policy.Enclaves = append(deployment.Policy.Enclaves, &buildRofl.EnclaveIdentity{
265+
ID: id.Enclave,
266+
})
255267
}
256268

257269
if err = manifest.Save(); err != nil {

cmd/rofl/deploy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ var (
6666

6767
manifestEnclaves := make(map[sgx.EnclaveIdentity]struct{})
6868
for _, eid := range deployment.Policy.Enclaves {
69-
manifestEnclaves[eid] = struct{}{}
69+
manifestEnclaves[eid.ID] = struct{}{}
7070
}
7171

7272
cfgEnclaves, err := roflCommon.GetRegisteredEnclaves(ctx, deployment.AppID, npa)

cmd/rofl/mgmt.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ var (
185185
ParaTime: npa.ParaTimeName,
186186
Admin: npa.AccountName,
187187
Debug: debugMode,
188-
Policy: &rofl.AppAuthPolicy{
188+
Policy: &buildRofl.AppAuthPolicy{
189189
Quotes: quote.Policy{
190190
PCS: &pcs.QuotePolicy{
191191
TCBValidityPeriod: 30,
@@ -217,7 +217,7 @@ var (
217217

218218
// Prepare transaction.
219219
tx := rofl.NewCreateTx(nil, &rofl.Create{
220-
Policy: *deployment.Policy,
220+
Policy: *deployment.Policy.AsDescriptor(),
221221
Scheme: idScheme,
222222
Metadata: manifest.GetMetadata(deploymentName),
223223
})
@@ -291,7 +291,7 @@ var (
291291

292292
updateBody := rofl.Update{
293293
ID: appID,
294-
Policy: *deployment.Policy,
294+
Policy: *deployment.Policy.AsDescriptor(),
295295
Metadata: manifest.GetMetadata(deploymentName),
296296
Secrets: secrets,
297297
}

0 commit comments

Comments
 (0)