Skip to content

Commit 73bb52a

Browse files
feat(rofl): upgrade possibility checks for artifacts
1 parent f730dfe commit 73bb52a

File tree

6 files changed

+139
-2
lines changed

6 files changed

+139
-2
lines changed

build/rofl/manifest.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,50 @@ func upgradeArtifacts(upgrade []artifactUpgrade) bool {
537537
return changed
538538
}
539539

540+
// upgradePossible checks if any explicitly configured artifact differs from the latest.
541+
//
542+
// This has intentionally different semantics than upgradeArtifacts:
543+
// - upgradeArtifacts: empty existing + non-empty new -> WRITES the new value
544+
// - upgradePossible: empty existing + non-empty new -> returns FALSE
545+
//
546+
// Rationale: When a manifest field is empty, the build uses the latest defaults
547+
// from code (LatestBasicArtifacts/LatestContainerArtifacts). So an empty field
548+
// means the user is already getting the latest, no notification needed. We only
549+
// notify when explicit overrides exist and are outdated.
550+
func upgradePossible(check []artifactUpgrade) bool {
551+
for _, artifact := range check {
552+
if artifact.new == "" {
553+
continue
554+
}
555+
if *artifact.existing != "" && *artifact.existing != artifact.new {
556+
return true
557+
}
558+
}
559+
return false
560+
}
561+
562+
// UpgradePossible returns true iff any explicitly set artifacts differ from latest.
563+
// Empty fields are ignored (they use defaults from code, so already latest).
564+
func (ac *ArtifactsConfig) UpgradePossible(latest *ArtifactsConfig) bool {
565+
if upgradePossible([]artifactUpgrade{
566+
{&ac.Builder, latest.Builder},
567+
{&ac.Firmware, latest.Firmware},
568+
{&ac.Kernel, latest.Kernel},
569+
{&ac.Stage2, latest.Stage2},
570+
}) {
571+
return true
572+
}
573+
return ac.Container.UpgradePossible(&latest.Container)
574+
}
575+
576+
// UpgradePossible returns true iff any explicitly set container artifacts differ from latest.
577+
func (cc *ContainerArtifactsConfig) UpgradePossible(latest *ContainerArtifactsConfig) bool {
578+
return upgradePossible([]artifactUpgrade{
579+
{&cc.Compose, latest.Compose},
580+
{&cc.Runtime, latest.Runtime},
581+
})
582+
}
583+
540584
// UpgradeTo upgrades the artifacts to the latest version by updating any relevant fields.
541585
//
542586
// Returns true iff any artifacts have been updated.

build/rofl/manifest_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,55 @@ func TestUpgradeArtifacts(t *testing.T) {
245245
changed = existing.UpgradeTo(&latest)
246246
require.False(changed)
247247
}
248+
249+
func TestUpgradePossible(t *testing.T) {
250+
require := require.New(t)
251+
252+
existing := ArtifactsConfig{
253+
Builder: "a",
254+
Firmware: "b",
255+
Kernel: "c",
256+
Stage2: "d",
257+
Container: ContainerArtifactsConfig{
258+
Runtime: "e",
259+
Compose: "f",
260+
},
261+
}
262+
latest := ArtifactsConfig{
263+
Firmware: "b2",
264+
Kernel: "c2",
265+
Stage2: "d2",
266+
Container: ContainerArtifactsConfig{
267+
Runtime: "e2",
268+
},
269+
}
270+
271+
// Explicit overrides differing from latest -> upgradeable.
272+
require.True(existing.UpgradePossible(&latest))
273+
274+
// After upgrading -> not upgradeable.
275+
existing.UpgradeTo(&latest)
276+
require.False(existing.UpgradePossible(&latest))
277+
278+
// Empty config (uses defaults from code) -> not upgradeable.
279+
require.False((&ArtifactsConfig{}).UpgradePossible(&latest))
280+
281+
// Partial: explicit override differs -> upgradeable.
282+
require.True((&ArtifactsConfig{Firmware: "old"}).UpgradePossible(&latest))
283+
284+
// Partial: explicit override matches latest -> not upgradeable.
285+
require.False((&ArtifactsConfig{Firmware: "b2"}).UpgradePossible(&latest))
286+
287+
// Container field differs -> upgradeable.
288+
require.True((&ArtifactsConfig{
289+
Container: ContainerArtifactsConfig{Runtime: "old"},
290+
}).UpgradePossible(&ArtifactsConfig{
291+
Container: ContainerArtifactsConfig{Runtime: "new"},
292+
}))
293+
294+
// ContainerArtifactsConfig directly.
295+
containerLatest := ContainerArtifactsConfig{Runtime: "new"}
296+
require.True((&ContainerArtifactsConfig{Runtime: "old"}).UpgradePossible(&containerLatest))
297+
require.False((&ContainerArtifactsConfig{Runtime: "new"}).UpgradePossible(&containerLatest))
298+
require.False((&ContainerArtifactsConfig{}).UpgradePossible(&containerLatest))
299+
}

cmd/rofl/build/build.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ var (
289289

290290
fmt.Println("Manifest enclave identities MATCH on-chain enclave identities.")
291291
}
292+
293+
// Check if artifact upgrades are available and notify the user.
294+
notifyUpgradeAvailable(manifest)
295+
292296
return nil
293297
}
294298

@@ -332,11 +336,45 @@ var (
332336

333337
fmt.Printf("Run `oasis rofl update` to update your ROFL app's on-chain configuration.\n")
334338
}
339+
340+
// Check if artifact upgrades are available and notify the user.
341+
notifyUpgradeAvailable(manifest)
342+
335343
return nil
336344
},
337345
}
338346
)
339347

348+
// notifyUpgradeAvailable checks if artifact upgrades are available and prints a notification.
349+
func notifyUpgradeAvailable(manifest *buildRofl.Manifest) {
350+
var latestArtifacts buildRofl.ArtifactsConfig
351+
switch manifest.TEE {
352+
case buildRofl.TEETypeTDX:
353+
switch manifest.Kind {
354+
case buildRofl.AppKindRaw:
355+
latestArtifacts = buildRofl.LatestBasicArtifacts
356+
latestArtifacts.Builder = buildRofl.LatestBuilderImage
357+
case buildRofl.AppKindContainer:
358+
latestArtifacts = buildRofl.LatestContainerArtifacts
359+
latestArtifacts.Builder = buildRofl.LatestContainerBuilderImage
360+
default:
361+
return
362+
}
363+
default:
364+
return
365+
}
366+
367+
current := manifest.Artifacts
368+
if current == nil {
369+
current = &buildRofl.ArtifactsConfig{}
370+
}
371+
372+
if current.UpgradePossible(&latestArtifacts) {
373+
fmt.Println()
374+
fmt.Println("NOTE: A new version of artifacts is available. Run `oasis rofl upgrade` to upgrade.")
375+
}
376+
}
377+
340378
// setupContainerEnv creates and initializes a container build environment.
341379
func setupContainerEnv(builderImage string) (env.ExecEnv, error) {
342380
baseDir, err := env.GetBasedir()

cmd/rofl/mgmt.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,8 @@ var (
595595
}
596596

597597
if artifactsUpdated {
598-
fmt.Printf("Run `oasis rofl build` to build your ROFL app.\n")
598+
fmt.Printf("Artifacts have been updated to the latest versions.\n")
599+
fmt.Printf("Run `oasis rofl build` to build with the new artifacts.\n")
599600
} else {
600601
fmt.Printf("Artifacts already up-to-date.\n")
601602
}

examples/rofl/upgrade.in.static

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
oasis rofl upgrade
1+
oasis rofl upgrade

examples/rofl/upgrade.out.static

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Artifacts have been updated to the latest versions.
2+
Run `oasis rofl build` to build with the new artifacts.

0 commit comments

Comments
 (0)