Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 83 additions & 40 deletions cmd/rofl/set_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (

"github.com/spf13/cobra"

"github.com/oasisprotocol/oasis-sdk/client-sdk/go/client"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/connection"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"

buildRofl "github.com/oasisprotocol/cli/build/rofl"
"github.com/oasisprotocol/cli/cmd/common"
Expand All @@ -16,45 +18,49 @@ import (
)

var setAdminCmd = &cobra.Command{
Use: "set-admin <new-admin>",
Short: "Change the administrator of the application in ROFL",
Use: "set-admin [<app-id>] <new-admin>",
Short: "Change the administrator of a ROFL",
Aliases: []string{"change-admin"},
Args: cobra.ExactArgs(1),
Args: cobra.RangeArgs(1, 2),
Run: func(_ *cobra.Command, args []string) {
cfg := cliConfig.Global()
npa := common.GetNPASelection(cfg)
txCfg := common.GetTransactionConfig()

manifest, deployment, npa := roflCommon.LoadManifestAndSetNPA(&roflCommon.ManifestOptions{
NeedAppID: true,
NeedAdmin: true,
})
var (
rawAppID string
newAdminArg string
manifest *buildRofl.Manifest
deployment *buildRofl.Deployment
)
switch len(args) {
case 2:
// Direct mode: oasis rofl set-admin <app-id> <new-admin>
rawAppID = args[0]
newAdminArg = args[1]
case 1:
// Manifest mode: oasis rofl set-admin <new-admin>
newAdminArg = args[0]
manifest, deployment, npa = roflCommon.LoadManifestAndSetNPA(&roflCommon.ManifestOptions{
NeedAppID: true,
NeedAdmin: true,
})
rawAppID = deployment.AppID
}

var appID rofl.AppID
if err := appID.UnmarshalText([]byte(deployment.AppID)); err != nil {
if err := appID.UnmarshalText([]byte(rawAppID)); err != nil {
cobra.CheckErr(fmt.Errorf("malformed ROFL app ID: %w", err))
}

npa.MustHaveAccount()
npa.MustHaveParaTime()

if deployment.Policy == nil {
cobra.CheckErr("no policy configured in the manifest")
}

oldAdminAddr, _, err := common.ResolveLocalAccountOrAddress(npa.Network, deployment.Admin)
if err != nil {
cobra.CheckErr(fmt.Errorf("bad current administrator address: %w", err))
}

newAdminAddr, newAdminEthAddr, err := common.ResolveLocalAccountOrAddress(npa.Network, args[0])
newAdminAddr, newAdminEthAddr, err := common.ResolveLocalAccountOrAddress(npa.Network, newAdminArg)
if err != nil {
cobra.CheckErr(fmt.Errorf("invalid new admin address: %w", err))
}

if *oldAdminAddr == *newAdminAddr {
fmt.Println("New admin is the same as the current admin, nothing to do.")
return
}

// When not in offline mode, connect to the given network endpoint.
ctx := context.Background()
var conn connection.Connection
Expand All @@ -63,45 +69,82 @@ var setAdminCmd = &cobra.Command{
cobra.CheckErr(err)
}

fmt.Printf("App ID: %s\n", appID)

updateBody := rofl.Update{
ID: appID,
Admin: newAdminAddr,
}

var oldAdminAddr *types.Address
if manifest != nil {
// Manifest mode: use local policy, metadata, secrets.
if deployment.Policy == nil {
cobra.CheckErr("no policy configured in the manifest")
}

oldAdminAddr, _, err = common.ResolveLocalAccountOrAddress(npa.Network, deployment.Admin)
if err != nil {
cobra.CheckErr(fmt.Errorf("bad current administrator address: %w", err))
}

updateBody.Policy = *deployment.Policy.AsDescriptor()
updateBody.Metadata = manifest.GetMetadata(roflCommon.DeploymentName)
updateBody.Secrets = buildRofl.PrepareSecrets(deployment.Secrets)
} else {
// Direct mode: reuse current policy, metadata, secrets from chain.
if txCfg.Offline {
cobra.CheckErr("direct mode requires network access")
}

appCfg, err := conn.Runtime(npa.ParaTime).ROFL.App(ctx, client.RoundLatest, appID)
cobra.CheckErr(err)

oldAdminAddr = appCfg.Admin
updateBody.Policy = appCfg.Policy
updateBody.Metadata = appCfg.Metadata
updateBody.Secrets = appCfg.Secrets
}

if oldAdminAddr != nil {
if *oldAdminAddr == *newAdminAddr {
fmt.Println("New admin is the same as the current admin, nothing to do.")
return
}
fmt.Printf("Old admin: %s\n", common.PrettyAddress(oldAdminAddr.String()))
}

newAdminStr := newAdminAddr.String()
if newAdminEthAddr != nil {
newAdminStr = newAdminEthAddr.Hex()
}

fmt.Printf("App ID: %s\n", deployment.AppID)
fmt.Printf("Old admin: %s\n", common.PrettyAddress(oldAdminAddr.String()))
fmt.Printf("New admin: %s\n", common.PrettyAddress(newAdminStr))

secrets := buildRofl.PrepareSecrets(deployment.Secrets)

tx := rofl.NewUpdateTx(nil, &rofl.Update{
ID: appID,
Policy: *deployment.Policy.AsDescriptor(),
Admin: newAdminAddr,
Metadata: manifest.GetMetadata(roflCommon.DeploymentName),
Secrets: secrets,
})
tx := rofl.NewUpdateTx(nil, &updateBody)

acc := common.LoadAccount(cliConfig.Global(), npa.AccountName)
acc := common.LoadAccount(cfg, npa.AccountName)
sigTx, meta, err := common.SignParaTimeTransaction(ctx, npa, acc, conn, tx, nil)
cobra.CheckErr(err)

if !common.BroadcastOrExportTransaction(ctx, npa, conn, sigTx, meta, nil) {
return
}

// Transaction succeeded — update the manifest with the new admin.
deployment.Admin = args[0]
if err = manifest.Save(); err != nil {
cobra.CheckErr(fmt.Errorf("failed to update manifest: %w", err))
// Transaction succeeded — update the manifest if available.
if manifest != nil {
deployment.Admin = newAdminArg
if err = manifest.Save(); err != nil {
cobra.CheckErr(fmt.Errorf("failed to update manifest: %w", err))
}
}

fmt.Printf("ROFL admin changed to %s.\n", common.PrettyAddress(newAdminStr))
},
}

func init() {
common.AddAccountFlag(setAdminCmd)
common.AddSelectorFlags(setAdminCmd)
setAdminCmd.Flags().AddFlagSet(common.RuntimeTxFlags)
setAdminCmd.Flags().AddFlagSet(roflCommon.DeploymentFlags)
}
30 changes: 17 additions & 13 deletions docs/rofl.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,29 +328,33 @@ their latest versions. This includes:
### Change ROFL app administrator {#set-admin}

Run `rofl set-admin` to transfer ownership of a ROFL app to a new
administrator. The transaction is signed by the current admin and, on success,
the manifest is updated with the new admin.
administrator. The ROFL app administrator owns the application, including
upgrades, policy changes and removal. The transaction must be signed by the
current admin.

If the current directory contains a ROFL manifest, the manifest is updated with
the new admin after a successful transaction.

![code shell](../examples/rofl/set-admin.in.static)

### Change ROFL machine administrator {#machine-set-admin}
To change the administrator directly on an existing app without a local
manifest, run:

Run `rofl machine set-admin` to change the administrator of an individual
machine instance.
![code shell](../examples/rofl/set-admin-address.in.static)

![code shell](../examples/rofl/machine-set-admin.in.static)
This mode requires network access and does not modify the manifest.

:::info ROFL admin vs machine admin
### Change ROFL machine administrator {#machine-set-admin}

The **ROFL admin** (changed via `oasis rofl set-admin`) owns the
application — transfer ownership, upgrades, policy changes, removal.
Run `rofl machine set-admin` to change the administrator of an individual
machine instance. This is independent of the ROFL app administrator and only
affects management of the specific machine instance.

The **machine admin** (changed via `oasis rofl machine set-admin`) manages
an individual machine instance — execution, restarts, stops.
![code shell](../examples/rofl/machine-set-admin.in.static)

These are independent roles.
To change the administrator of the machine without a local manifest, run:

:::
![code shell](../examples/rofl/machine-set-admin-address.in.static)

### Remove ROFL app from the network {#remove}

Expand Down
1 change: 1 addition & 0 deletions examples/rofl/machine-set-admin-address.in.static
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
oasis rofl machine set-admin oasis1qp2ens0hsp7gh23wajxa4hpetkdek3swyyulyrmz:000000000000055c bob
2 changes: 1 addition & 1 deletion examples/rofl/machine-set-admin.in.static
Original file line number Diff line number Diff line change
@@ -1 +1 @@
oasis rofl machine set-admin [<machine-name> | <provider-address>:<machine-id>] <new-admin>
oasis rofl machine set-admin bob
1 change: 1 addition & 0 deletions examples/rofl/set-admin-address.in.static
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
oasis rofl set-admin rofl1qpw7gxp7dqq72sdtpv4jrmdfys9nsp73wysglhue bob
2 changes: 1 addition & 1 deletion examples/rofl/set-admin.in.static
Original file line number Diff line number Diff line change
@@ -1 +1 @@
oasis rofl set-admin <new-admin>
oasis rofl set-admin bob
Loading