Skip to main content
Unlisted page
This page is unlisted. Search engines will not index it, and only users having a direct link can access it.

Encrypted JavaScript delivery

Registered V5 release required

The encrypted build, job-bound key release, payload loading and application completion were verified in production on 6 September 2026 with Actions v1.3.2 and runtime SDK 0.3.30. This recipe requires registered V5 source publication. Its general customer release remains gated separately; the capability matrix is the availability authority.

The build encrypts your application module before upload. IPFS carries a public bootstrap, a public descriptor and ciphertext. The bootstrap obtains the key through the existing job-bound managed Lockbox grant, verifies both payload digests and AES-GCM authentication, and loads the module inside the processor. PROOF can access the managed key during release. This protects the payload from public artifact readers; it is not operator-blind code delivery, and it does not establish Cargo image or cache confidentiality.

Prepare the module and key

Use Actions v1.3.2 or a compatible later @v1; its public loader includes runtime SDK 0.3.30. Use CLI 0.13.0 or later for the paused publication flags below. The server must support registered publication previews and atomic setup holds.

Your build produces a self-contained CommonJS module at dist/encrypted.cjs with an exported start(runtime) function. Use the supplied, already bootstrapped runtime handle; do not start another runtime bootstrap. Include all application dependencies in this module. The encrypted mode accepts one module of at most 16 MiB, and rejects extra files, prepared artifacts, custom artifact metadata and reused CIDs.

import type { BootstrapSlipwayRuntimeHandle } from "@proof-computer/liskov-runtime";

export async function start(runtime: BootstrapSlipwayRuntimeHandle): Promise<void> {
await runtime.diagnostics.report({
stage: "application.completed",
status: "succeeded",
code: "work_completed"
});
runtime.stop();
}

Generate a cryptographically random 32-byte key and encode it as canonical standard base64. Store it as a GitHub repository secret, for example APPLICATION_CODE_KEY. Keep the same value available for the Application's managed secret setup. Never commit the key or print it in a build step.

Declare the required secret in the V5 manifest's configuration.secrets:

{
"secretId": "application-code-key",
"required": true,
"destination": {"kind": "environment", "name": "LISKOV_CODE_KEY"}
}

Use release.mode: source, JavaScript with the nodejs engine, and runtime.entrypoint.file: encrypted.cjs. Keep the secret ID identical in the manifest and workflow. Set the intended execution mode, paid duration and Service Credit cap deliberately: publishing a once policy normally starts one paid occurrence.

The processor must provide a working P-256 key for encrypted grant responses. Acurast's Android implementation requires Android 12 or later for this key agreement; a DataEncryption advertisement alone does not establish P-256 support. Use a processor with verified P-256 support. To select it explicitly, set deployment.placement.processorSelection.mode: exact and supply its address in processorIds; see the V5 manifest reference.

Build, encrypt, pin and attest

The Application identity and its source binding must already authorize the exact repository, ref, caller workflow and manifest path. Add a caller workflow:

.github/workflows/encrypted-code.yml
name: Encrypted JavaScript artifact
on:
workflow_dispatch:
permissions:
contents: read
id-token: write
jobs:
artifact:
uses: proof-computer/liskov-github-actions/.github/workflows/acurast-app.yml@v1
with:
app-id: encrypted-worker
authored-manifest-path: .liskov/encrypted-worker.json
entrypoint: encrypted.cjs
encryption-mode: aes-256-gcm-payload-v1
encryption-secret-id: application-code-key
ipfs-gateway-url: "https://ipfs-upload.liskov.proof.computer/ipfs/{cid}"
secrets:
LISKOV_CODE_ENCRYPTION_KEY: ${{ secrets.APPLICATION_CODE_KEY }}

The workflow runs the caller's typecheck, tests and build. It encrypts with a fresh AES-256-GCM nonce, verifies the uploaded bytes through the specified gateway, and attests the artifact through GitHub OIDC. It does not publish the policy, configure Lockbox, or spend Service Credits.

Download the run's build manifest. Record scriptIpfs, scriptHash, the encryptedCode descriptor, exact source commit, source-binding revision and revocation epoch. The Attest artifact pin step reports the source-... artifact version. The outer ZIP digest, plaintext digest and ciphertext digest identify different bytes; never substitute one for another.

Publish paused, then configure the key

Using those exact values, preview the registered source publication:

proof liskov application policy publish encrypted-worker \
--file .liskov/encrypted-worker.json \
--artifact-digest sha256:YOUR_ZIP_DIGEST \
--binding-revision 1 --revocation-epoch 0 \
--source-ref refs/heads/main --source-commit YOUR_SOURCE_COMMIT \
--workflow-identity OWNER/REPOSITORY/.github/workflows/encrypted-code.yml@refs/heads/main \
--expected-pointer-version 0 \
--paused --reason "Configure application code key before execution" --dry-run

Replace the example identity, revisions, pointer and digest with the readback for your Application. Review the proposed policy and artifact. Repeat the same command with --yes in place of --dry-run to commit the policy and pause atomically. Check that the Application reads paused with the expected policy version, digest and artifact. A stale pointer refuses publication; read and review the new state before confirming again.

Open the Application's Secrets settings and set application-code-key to the same base64 value used by the build. Confirm that the save succeeds before resuming. The declarations list describes required inputs; it does not report whether the stored value is present. Pause must cover this setup: a required missing key blocks runtime readiness after deployment, and is not a pre-launch spend hold.

When the key and spend authority are ready, resume deliberately:

proof liskov application resume encrypted-worker \
--reason "Start the reviewed encrypted application" --yes

Verify the processor result

Require the signed runtime diagnostic application.encrypted_code.loaded, status succeeded, code encrypted_code_verified. Compare the plaintext and ciphertext digests in the attested descriptor; loader success means both were verified. Also verify an application-specific completion or health event. Loader success proves authenticated loading; it does not prove your application's business result. For a one-shot run, record terminal job state and the settled Service Credit amount.

The loader accepts only a key installed from the matching authenticated Lockbox grant. Setting an environment variable alone is insufficient. It uses a runtime home inside the processor job directory, creates it when needed, loads a private CommonJS module, and removes the temporary plaintext file and module-cache entry after start(runtime) completes. It does not use a shared plaintext cache.

A lockbox_response_key_missing bootstrap failure means the processor did not provide its P-256 grant-response key. The managed application code key is a separate key. Hold further attempts and report the stable failure code and job identity to support, together with the processor's Android version when available.

If startup reports encrypted_code_start_failed, inspect the accompanying encrypted_code_failure_detail diagnostic. Its bounded phase identifies descriptor validation, key release, ciphertext verification, directory or module creation, module loading, or application startup without exposing the key, plaintext, local path, or exception text. Compare the attested digests, secret ID and configured key version. Let an existing one-shot occurrence settle, then retire it or pause future launches before retrying. Do not print the key or decrypted module to diagnose it. See build and publication troubleshooting.