Skip to content

enforce ChainSubmit revocation at broadcast + unskip the rejection specs #234

Description

@Imod7

Tracking: carried over from #97 (Group 4)

Description

Three e2e specs are skipped/weakened because a revoked ChainSubmit permission does not currently make a broadcast fail:

  • examples/tx-demo/e2e/signing-rejected.spec.ts: skipped
  • examples/contracts-demo/e2e/signing-rejected.spec.ts: skipped
  • examples/signer-demo/e2e/permission.spec.ts: runs, but with a weakened assertion

Why this is the real bug (correction to #97's original framing)

#97's Group 4 section ("signer-demo permission-rejection contract") framed this as "the permission is checked once at connect, not per-sign: converge on a permission-rejection contract that applies per-sign." A code map showed that framing is not how the code works:

  • The product-sdk signer only requests ChainSubmit once at connect (packages/signer/src/providers/host.ts:610). It does not, and is not meant to, enforce permissions per sign.
  • Enforcement is the host/container's job. Per the fake host's (the host SDK test - @parity/host-api-test-sdk) own CLAUDE.md: "Signing is NOT gated behind any permission - real hosts don't do this. ChainSubmit is enforced by the container at transaction_broadcast level."
  • The fake host's setEnforcePermissions is a dead flag: set at host-runtime.ts:1300, the backing variable (:142) is never read, and the signing handlers (:577–647) aren't gated at all.

So the bug is: the fake host doesn't enforce ChainSubmit revocation at broadcast, so the revoke-then-sign spec can't go red. The durable fix is to let the real container enforce it and unskip against the headless host; the interim fix is to wire the dead flag in the fake host.

Fix (interim - only if the headless host is far off)

In host-api-test-sdk, src/browser/host-runtime.ts: gate the ChainSubmit / transaction_broadcast slot on grantedPermissions.has("ChainSubmit") so that revokePermission("ChainSubmit") + reject-all makes the broadcast fail with PermissionDenied. That propagates back as the TxSigningRejectedError the specs already assert. Then:

  • bump the catalog pin in product-sdk (pnpm-workspace.yaml: ^0.9.0 → new), and
  • revert the 3 skips (tx-demo + contracts-demo signing-rejected.spec.ts) and restore the strong assertion in signer-demo/permission.spec.ts.

The durable version is the "Headless-host migration" first checklist item in the #235 issue under the "Gated on the headless host existing": the real container enforces ChainSubmit and we unskip against the headless host. Don't do a big test-SDK rewrite either way.

Done when

  • revokePermission("ChainSubmit") causes a broadcast to fail with PermissionDenied → surfaces as TxSigningRejectedError.
  • tx-demo/e2e/signing-rejected.spec.ts and contracts-demo/e2e/signing-rejected.spec.ts unskipped and green.
  • signer-demo/e2e/permission.spec.ts strong assertion restored.
  • pnpm test:e2e exits 0 with these specs running.

Key references

Thing Path
Signer host provider (ChainSubmit request at connect) product-sdk/packages/signer/src/providers/host.ts:595–618
Permissions module product-sdk/packages/host/src/permissions.ts:134
Fake host runtime (perm handler :379–406, signing :577–647, dead flag :142,:1300) host-api-test-sdk/src/browser/host-runtime.ts

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions