@zuke/signpath

← API reference

`@zuke/signpath` — Authenticode signing through

Symbols

#

SignPathApiError

class
class SignPathApiError extends Error

SignPath refused a call: a non-2xx status that is not a transient one the transport retried.

try {
  await SignPathTasks.status((s) => s.signingRequestId(id));
} catch (error) {
  if (error instanceof SignPathApiError && error.status === 401) {
    // the API token is wrong or expired
  }
}
MemberSignatureDoc
name name: string The error name.
method method: string The HTTP method of the failing call.
path path: string The endpoint path, such as /v1/<org>/SigningRequests (never the host).
status status: number The HTTP status of the answer.
detail detail: string | undefined What SignPath said, when it said anything: the error, detail, title or message of a JSON answer, or the start of a plain-text one. Scrubbed of credentials and control characters, and capped in length.
#

SignPathConnectionSettings

class
class SignPathConnectionSettings

The connection half of every SignPath call's settings.

MemberSignatureDoc
organizationId organizationId(id: string): this The SignPath organization id — the GUID in the web app's URLs and under *Organization settings*. Defaults to the SIGNPATH_ORGANIZATION_ID environment variable.
apiToken apiToken(token: string): this The API token of a SignPath user with submitter permission on the project's signing policy, sent as Authorization: Bearer <token>. Defaults to the SIGNPATH_API_TOKEN environment variable. The token never reaches a progress line or an error message: every message this package builds is scrubbed of it. Declare it in the build as a parameter(...).secret() so Zuke masks it in its own output too.
apiUrl apiUrl(url: string): this The REST API's base URL, https://app.signpath.io/Api by default; the version and organization (/v1/<org>/…) are appended. It carries the token, so it must be https: unless it is loopback or ZUKE_ALLOW_INSECURE_URL is set. The web app's links in errors and progress lines use the same origin (<origin>/Web/<org>/…).
requestTimeout requestTimeout(duration: string | number): this Abort one API call after this long ("30s", or ms); default one minute.
downloadTimeout downloadTimeout(duration: string | number): this Abort a signed-artifact download that has not finished after this long ("10m", or ms); default five minutes.
maxDownloadBytes maxDownloadBytes(bytes: number): this Refuse a signed artifact larger than this many bytes; default 2 GiB.
retries retries(count: number): this Retry a transient failure this many times (default 3), with a doubling delay from one second. A status poll or a download is retried after a network error, a timeout, or HTTP 429, 502, 503 or 504; a submission only after 429 or 503, the answers that say the request was not processed, so a retry cannot create a second signing request.
fetch fetch(fetcher: fetch): this Send with this fetch instead of the global one — the seam tests use.
readEnv readEnv(reader: unknown): this Read environment variables through reader instead of Deno.env.
sleep sleep(sleeper: unknown): this Wait through sleeper instead of a timer — the seam tests use.
now now(clock: unknown): this Read the time from clock (epoch ms) instead of Date.now.
log log(sink: unknown): this Send progress lines to sink instead of console.log.
organizationId_? organizationId_?: string The organization id (set by organizationId); else read from the environment.
apiToken_? apiToken_?: string The API token (set by apiToken); else read from the environment.
apiUrl_ apiUrl_: string The REST API's base URL (set by apiUrl).
requestTimeout_ requestTimeout_: number The per-call timeout in ms (set by requestTimeout).
downloadTimeout_ downloadTimeout_: number The signed-artifact download timeout in ms (set by downloadTimeout).
maxDownloadBytes_ maxDownloadBytes_: number The signed-artifact size cap in bytes (set by maxDownloadBytes).
retries_ retries_: number How many times a transient failure is retried (set by retries).
fetch_ fetch_: fetch The fetch to use (set by fetch); the global one by default.
readEnv_ readEnv_: unknown The environment reader (set by readEnv).
sleep_ sleep_: unknown How the task waits between polls and retries (set by sleep).
now_ now_: unknown The clock, in epoch ms (set by now).
log_ log_: unknown Where progress lines go (set by log); console.log by default.
#

SignPathDownloadSettings

class
class SignPathDownloadSettings extends SignPathStatusSettings

Settings for SignPathTasks.download: the connection, the signing request's id, and where to write the signed artifact.

MemberSignatureDoc
output output(path: PathLike): this The file to write the signed artifact to; its directory is created when missing, and an existing file is replaced. Required.
output_? output_?: string Where to write the signed artifact (set by output).
#

SignPathGitHubOriginSettings

class
class SignPathGitHubOriginSettings

Where the artifact to sign lives in GitHub Actions. Only the artifact id is required: the run, repository and token default to the workflow's own environment (GITHUB_RUN_ID, GITHUB_REPOSITORY, GITHUB_TOKEN).

await SignPathTasks.submit((s) =>
  s.projectSlug("zuke").signingPolicySlug("release-signing")
    .gitHubOrigin((g) => g.artifactId(artifactId).token(githubToken))
    .output("dist/signed/zuke.zip")
);
MemberSignatureDoc
artifactId artifactId(id: string | number): this The id of the artifact actions/upload-artifact (v4 or later) uploaded — its artifact-id step output. Required.
runId runId(id: string | number): this The workflow run the artifact belongs to; defaults to GITHUB_RUN_ID.
repository repository(name: string): this The repository, owner/name; defaults to GITHUB_REPOSITORY.
token token(value: string): this The GitHub token the connector reads the run and downloads the artifact with — the workflow's GITHUB_TOKEN (with actions: read and contents: read) is enough. Defaults to the GITHUB_TOKEN environment variable. It is masked out of every message, like the API token. The workflow's own token stops working when the workflow ends, so the task must wait for SignPath to fetch the artifact; submit always waits.
connectorUrl connectorUrl(url: string): this The SignPath GitHub connector to submit through; SignPath's hosted GitHub.com one by default. Only a self-hosted GitHub Enterprise Server needs another. It carries the API token, so it must be https:.
artifactId_? artifactId_?: string The workflow artifact's id (set by artifactId).
runId_? runId_?: string The workflow run's id (set by runId); else GITHUB_RUN_ID.
repository_? repository_?: string The repository, owner/name (set by repository); else GITHUB_REPOSITORY.
token_? token_?: string The GitHub token (set by token); else GITHUB_TOKEN.
connectorUrl_ connectorUrl_: string The connector's URL (set by connectorUrl).
#

SignPathRequestError

class
class SignPathRequestError extends Error

A SignPath call produced no usable answer: it could not be sent, it timed out, it was redirected somewhere it must not follow, the download was larger than allowed, or the answer was not shaped as SignPath documents it.

MemberSignatureDoc
name name: string The error name.
method method: string The HTTP method of the failing call.
path path: string The endpoint path, such as /v1/<org>/SigningRequests (never the host).
#

SignPathSignedArtifact

interface
interface SignPathSignedArtifact

A signed artifact written to disk by SignPathTasks.download or submit.

MemberSignatureDoc
path path: string The path it was written to — the one configured with .output(...).
bytes bytes: number Its size in bytes.
#

SignPathSigningError

class
class SignPathSigningError extends Error

A signing request reached a final status other than Completed — it was Denied by an approver, Failed (a malware scan, a processing error, an artifact SignPath could not retrieve) or Canceled.

MemberSignatureDoc
name name: string The error name.
signingRequestId signingRequestId: string The signing request's id.
status status: string The final status, such as Denied.
workflowStatus workflowStatus: string | undefined The finer-grained workflow status, such as MalwareDetected, when sent.
webUrl webUrl: string The signing request's page in the SignPath web app.
#

SignPathSigningRequestStatus

interface
interface SignPathSigningRequestStatus

Where a signing request stands, from GET …/SigningRequests/<id>/Status.

SignPath documents these status values: InProgress, WaitingForApproval, Completed, Failed, Denied and Canceled — the last four final. workflowStatus is finer-grained (Submitted, RetrievingArtifact, ScanningForMalware, Processing, MalwareDetected, ArtifactRetrievalFailed, …). Both are kept as the strings SignPath sent, so a value added later still reads.

MemberSignatureDoc
signingRequestId signingRequestId: string The signing request's id, a GUID.
status status: string The status, such as InProgress or Completed.
workflowStatus workflowStatus: string | undefined The workflow status, such as ScanningForMalware, when sent.
isFinalStatus isFinalStatus: boolean Whether the request will not change any more: SignPath's isFinalStatus, or — should an answer leave it out — whether status is one of the four documented final ones.
webUrl webUrl: string The signing request's page in the SignPath web app.
#

SignPathStatusSettings

class
class SignPathStatusSettings extends SignPathConnectionSettings

Settings for SignPathTasks.status: the connection and the request's id.

MemberSignatureDoc
signingRequestId signingRequestId(id: string): this The signing request to read — the GUID submit returned. Required.
signingRequestId_? signingRequestId_?: string The signing request's id (set by signingRequestId).
#

SignPathSubmission

interface
interface SignPathSubmission

What SignPathTasks.submit did: the request, its outcome, the download.

MemberSignatureDoc
signingRequestId signingRequestId: string The new signing request's id, a GUID.
webUrl webUrl: string The signing request's page in the SignPath web app.
status status: SignPathSigningRequestStatus The final status — always Completed; anything else throws.
signedArtifact signedArtifact: SignPathSignedArtifact | undefined The signed artifact, when .output(...) asked for it to be downloaded.
#

SignPathSubmitSettings

class
class SignPathSubmitSettings extends SignPathConnectionSettings

Settings for SignPathTasks.submit.

MemberSignatureDoc
projectSlug projectSlug(slug: string): this The SignPath project's slug. Required.
signingPolicySlug signingPolicySlug(slug: string): this The signing policy's slug, such as release-signing — it decides the certificate and whether an approver must sign off. Required.
artifactConfigurationSlug artifactConfigurationSlug(slug: string): this The artifact configuration's slug — which files inside the artifact are signed, and how. The project's default configuration when unset.
description description(text: string): this A description shown on the request, such as the version being released.
parameter parameter(name: string, value: string): this A user-defined parameter the artifact configuration reads (a version number to stamp, say). Names are letters, digits, ., - and _. Repeatable.
artifact artifact(path: PathLike): this Upload this local file as the artifact (SubmitWithArtifact). Exactly one of artifact and gitHubOrigin is required. SignPath's open-source programme accepts only builds whose origin it can verify, so for it use gitHubOrigin instead.
gitHubOrigin gitHubOrigin(configure: Configure<SignPathGitHubOriginSettings>): this Have SignPath fetch the artifact from a GitHub Actions workflow run and verify its origin. Exactly one of artifact and gitHubOrigin is required.
output output(path: PathLike): this Download the signed artifact to this file once the request completes; its directory is created when missing. Without it, submit only waits.
timeout timeout(duration: string | number): this Fail with a SignPathTimeoutError when the request is not final after this long ("30m", or ms); default ten minutes. A policy that needs a manual approval wants longer.
pollInterval pollInterval(duration: string | number): this Poll the request's status this often ("5s", or ms; at least one second); default ten seconds.
projectSlug_? projectSlug_?: string The project's slug (set by projectSlug).
signingPolicySlug_? signingPolicySlug_?: string The signing policy's slug (set by signingPolicySlug).
artifactConfigurationSlug_? artifactConfigurationSlug_?: string The artifact configuration's slug (set by artifactConfigurationSlug).
description_? description_?: string The request's description (set by description).
parameters_ parameters_: Array<unknown> User-defined parameters, in the order set (set by parameter).
artifact_? artifact_?: string A local file to upload (set by artifact).
gitHubOrigin_? gitHubOrigin_?: SignPathGitHubOriginSettings A GitHub Actions artifact to fetch (set by gitHubOrigin).
output_? output_?: string Where to write the signed artifact (set by output).
timeout_ timeout_: number How long to wait for the request to finish, in ms (set by timeout).
pollInterval_ pollInterval_: number How often to poll its status, in ms (set by pollInterval).
#

SignPathTasks

const
const SignPathTasks: SignPathTasksApi

Typed task functions for SignPath's code-signing service.

#

SignPathTasksApi

interface
interface SignPathTasksApi

The operations SignPathTasks exposes.

MemberSignatureDoc
submit submit(configure: Configure<SignPathSubmitSettings>): Promise<SignPathSubmission> Submit a signing request, wait for it to complete, and — with .output(path) — download the signed artifact. ``ts const { signingRequestId } = await SignPathTasks.submit((s) => s.organizationId(orgId).apiToken(token) .projectSlug("zuke").signingPolicySlug("release-signing") .gitHubOrigin((g) => g.artifactId(artifactId)) .timeout("30m").output("dist/signed/zuke.zip") ); ``
status status(configure: Configure<SignPathStatusSettings>): Promise<SignPathSigningRequestStatus> Read a signing request's status once — no waiting. ``ts const { status } = await SignPathTasks.status((s) => s.signingRequestId(id) ); ``
download download(configure: Configure<SignPathDownloadSettings>): Promise<SignPathSignedArtifact> Download a completed signing request's signed artifact. ``ts await SignPathTasks.download((s) => s.signingRequestId(id).output("dist/signed/zuke.exe") ); ``
#

SignPathTimeoutError

class
class SignPathTimeoutError extends Error

A signing request was still not final when the wait ran out — typically one waiting for a manual approval. The request is left as it is; approve it and fetch the result later with SignPathTasks.download.

MemberSignatureDoc
name name: string The error name.
signingRequestId signingRequestId: string The signing request's id.
status status: string The last status seen, such as WaitingForApproval.
timeoutMs timeoutMs: number How long the wait lasted, in milliseconds.
webUrl webUrl: string The signing request's page in the SignPath web app.
#

SignPathValidationError

class
class SignPathValidationError extends Error

The SignPath GitHub connector refused to create the signing request because the build's origin did not verify — the artifact is not from this workflow run, a job ran on a self-hosted runner, the GitHub token cannot read the run, and the like. issues lists what the connector reported.

MemberSignatureDoc
name name: string The error name.
issues issues: unknown The validation errors, in the order the connector reported them.
#

SignPathValidationIssue

interface
interface SignPathValidationIssue

One build-system validation error the GitHub connector reported.

MemberSignatureDoc
error error: string What failed, as the connector worded it (scrubbed and capped).
howToFix howToFix: string | undefined The connector's advice on fixing it, when it gave any.
#

SigntoolHashAlgorithm

type
type SigntoolHashAlgorithm = SHA1 | SHA256

The digest algorithms /hash accepts.

#

SigntoolTasks

const
const SigntoolTasks: SigntoolTasksApi

Typed task functions for the Windows SDK's signtool.

#

SigntoolTasksApi

interface
interface SigntoolTasksApi

The shape of SigntoolTasks.

MemberSignatureDoc
verify verify(configure: Configure<SigntoolVerifySettings>): Promise<CommandOutput> Check a file's Authenticode signature with signtool verify; a file that is unsigned or fails the policy exits non-zero, which throws unless .noThrow() is set.
#

SigntoolVerifySettings

class
class SigntoolVerifySettings extends ToolSettings

Settings for signtool verify.

MemberSignatureDoc
authenticodePolicy authenticodePolicy(): this Verify against the default Authenticode policy (/pa) — what a signed .exe or .msi needs. Without it signtool applies the Windows driver policy and rejects ordinary code-signing certificates.
kernelPolicy kernelPolicy(): this Verify against the kernel-mode driver signing policy (/kp).
policy policy(guid: string): this Verify against the policy with this GUID (/pg).
allSignatures allSignatures(): this Verify every signature of a file that carries several (/all).
signatureIndex signatureIndex(index: number): this Verify only the signature at this index, from 0 (/ds).
hash hash(algorithm: SigntoolHashAlgorithm): this Look the file up in a catalog only for this digest algorithm (/hash).
catalog catalog(path: PathLike): this Verify against this catalog file (/c).
rootSubjectName rootSubjectName(name: string): this Require the signing certificate to chain to a root whose subject name contains this text (/r).
timestampWarning timestampWarning(): this Warn when the signature is not timestamped (/tw).
description description(): this Print the signature's description and URL (/d).
verbose verbose(): this Print the signer, the chain and the timestamp (/v).
debug debug(): this Print debugging information (/debug).
file file(...paths: PathLike[]): this The files to verify (positional), at least one. A relative path that starts with - is passed as ./-… so it cannot be read as an option; one that starts with / is refused, since signtool would read it as an option and on Windows it means the current drive's root — give a drive-qualified or a relative path instead.