TAPS Node and SoveDocs
Use a self-hosted or hosted TAPS Node, or SoveDocs, for protected files with main.yaml, a local install, revoke, activity and sharing.
TAPS (Trust Anchor Provenance System) is HubXero Labs' open protocol for files that carry their own identity, provenance and policy and open only when a TAPS Node issues a licence. These three drivers serve protect: a self-hosted TAPS Node (the container from the SDK), a hosted TAPS Node, or SoveDocs. Pick them for exam papers nobody can open early, tenders, results or any document you may need to revoke.
Interfaces it serves
Pick TAPS Node and SoveDocs in main.yaml for any of these. Your calls stay the same, and you can swap later.
protectBuilding for 0.4Driver taps-node Self-hosted TAPS Node
In @mainsdk/protect-taps
protect:
driver: taps-nodeSwap to another provider
protectBuilding for 0.4Driver taps-hosted Hosted TAPS Node
In @mainsdk/protect-taps
protect:
driver: taps-hostedSwap to another provider
protectBuilding for 0.4Driver sovedocs SoveDocs
In @mainsdk/protect-taps; conformance follows taps-node
protect:
driver: sovedocsSwap to another provider
deviceBuilding for 1.3Driver taps TAPS credentials, attestation and delegationFrom the device-taps spec
In @mainsdk/device-taps
device:
driver: tapsSwap to another provider
Before you start
- Choose where the node runs: your own
taps-nodecontainer, a hosted TAPS Node, or SoveDocs. - Make the app's issuer identity with
mainsdk seal keygenand keep it as a secret:MAINSDK_PROTECT_KEY. - Hardware attestation roots, HSMs and identity providers are ports your deployment supplies; MainSDK does not run them.
Install
@mainsdk/protect-taps is private and is not published to npm. It depends on @taps/* (the TAPS TypeScript SDK) through link: folders, which the owner approved for this stage.
- Check out the TAPS SDK next to your project:
taps-sdk-typescriptat tagv0.2.0. - Add
@mainsdk/protect-tapsfrom your MainSDK workspace and runpnpm install. - Pass the driver to the app:
createApp({ protect: tapsNode }).
import { createApp } from "mainsdk";
import { tapsNode } from "@mainsdk/protect-taps";
export const app = createApp({ protect: tapsNode });CI checks out taps-sdk-typescript at v0.2.0 in its own job, so a folder that moves is caught there. Application code never imports @taps/*: mainsdk check reports one that does as MAIN-PROTECT-0020. In production, @taps/* must come from the registry, not a folder: a build that resolves it from link: or file: fails with MAIN-PROTECT-0022.
Configure
protect:
driver: taps-node # taps-node | taps-hosted | sovedocs
url: https://taps.acme.dev # the TAPS Node
share-domain: open.acme.dev # where the Web Reader runs
key: secret:MAINSDK_PROTECT_KEY # the app's issuer identity
mode: viewer # viewer | wrapper
suite: TAPS-CS1 # TAPS-CS1 | TAPS-CS2
renew: 10s # licence renewal, 5s to 5murl, share-domain and key are required for all three drivers. The hosts (the Node, the share domain, any threshold party and the sealing service) are added to the network allowlist, and every request goes through it with its timeouts and retries. For every key, see Protected files.
Use it
"use server";
import { auth, protect, share } from "mainsdk";
export async function publishPaper(req: Request, paper: File, examiners: string[]) {
await auth.require(req, { role: "exam-admin" });
const asset = await protect(paper, {
label: "sensitive",
policy: { releaseAt: "2027-03-01T09:00:00Z" }, // no licence before this time
});
const { url } = await share(asset, { to: examiners });
return url; // a getqr.id link that opens the TAPS Web Reader
}
export async function pullPaper(req: Request, assetId: string) {
await auth.require(req, { role: "exam-admin", fresh: "5m" });
await protect.revoke(assetId, { reason: "paper leaked" }); // the next open and renew fail
return protect.activity(assetId); // who opened it
}Local development and testing
Use createTestApp() from @mainsdk/testing. It runs the local driver offline with the test clock and adds app.protect.signals(), app.protect.party(name) and app.protect.chain(). Nothing in a test reaches a TAPS Node. Run the mainsdk suite against taps-node in your own CI, where the Node container is available.
What MainSDK adds on top
- Ciphertext without a licence, wherever a copy ends up.
- Revocation within one
renewinterval. - Opens and revocations in the MainSDK decision log as well as the TAPS ledger, on the eight
mainsdk:protect.*channels. - Each user is a tenant-pairwise principal to the Node: no user id, email or name reaches it in clear.
- Share links and QR codes through getqr.id, with "Powered by getqr.id".
- Check codes
MAIN-PROTECT-0020to0022for imports, the section and production installs.
See Protected files.
Limits and notes
- The TAPS ledger runs in process in this release.
- A suite of
TAPS-CS3is refused withMAIN-PROTECT-0010until it is registered. MainSDK claims no post-quantum protection forprotect. - The package installs from a local folder, so it is private and not on npm. That changes when
@taps/*is published. - Gaps in a driver (
query,threshold,timelock,inspect,web3,delivery) are listed in the driver profile; a call it lacks fails withMAIN-PROTECT-0019. - A TAPS Node, threshold party or sealing service is not run inside MainSDK. An unreachable Node fails opens with
MAIN-PROTECT-0014and the rest of the app keeps serving. - Fleet adds an estate view of protected files and a revoke-since-a-date response action.
Swap to or from it
protect:
driver: taps-hosted # was taps-nodeFAQ
Do readers need to install anything? No. Links open in the TAPS Web Reader.
Can I use the TAPS SDK directly? Not in app code. Import protect from mainsdk; the driver package is the only place that imports @taps/*.
Next
- Protected files: every call and key.
- Share links and QR codes: how protected files are shared.
- Errors: every
MAIN-PROTECT-*code.
Was this page helpful?