Collects versioned evidence documents and extracted text
epack install collector documents
Adds to epack.yaml, resolves dependencies, downloads binary.
Run all configured collectors and build a pack:
epack collect
Runs all collectors in epack.yaml and outputs an evidence pack.
Or add manually to epack.yaml:
collectors:
documents:
source: https://github.com/locktivity/epack-collector-documents
Then run epack install to lock and sync.
The Documents collector adds your Locktivity evidence documents to evidence
packs, so your policies and reports travel with the rest of your evidence.
You manage documents in Locktivity: upload them, or connect a source like
GitHub or Google Drive. When a pipeline runs, this collector adds the
documents you selected for that pipeline to the pack.
Each run adds a folder per document under artifacts/documents/<id>/,
plus one index:
artifacts/documents.json): every document with its
name, source, and version, pointing to that document's files.Each file is verified against its recorded checksum before it is packed.
artifacts/
documents.json # the index
documents/
doc_4f2a9c/
acme-soc2-2025.pdf # the document, ready to open
text.json # extracted text with citations
metadata.json # extracted details with citations
doc_7b3e1f/
access-policy.pdf # rendered from the linked source
access-policy.md # the original source file
text.json
Field-level schemas for the index and text artifacts live in
schema/.
Each entry in documents.json describes one document:
| Field | What It Tells You |
|---|---|
name, source, version_number |
Which document this is, where it lives, and which version shipped. |
document_type |
What kind of document Locktivity recognized, such as a SOC 2 report or a penetration test. |
file, source_file, text, metadata |
Where each of the document's files landed in the pack, with a digest for each downloaded file. source_file appears when the shipped file is a rendering of a linked source. |
warnings |
Anything incomplete: a document with no file yet, or text not extracted yet. |
captured_at, run_key, digest (top level) |
When the document set was captured, the run it belongs to, and the integrity hash of the whole set. |
Which documents a pipeline carries is decided in Locktivity, on the pipeline's
Documents collector: all of your documents, or a chosen subset. The collector
follows that selection, and there's nothing to configure here.
On a Locktivity-managed pipeline, a short-lived token is issued automatically
for each run, so no long-lived secret is stored in your CI settings. In your
own CI, the collector exchanges an API application's client credentials for a
short-lived token on each run.
See Configuration for setup instructions.
When you add the Documents collector to a pipeline in Locktivity, the pipeline
generates the collector configuration. At runtime, the pipeline credential
provides a token for the collector:
credential_sets:
locktivity_documents: "<credential-set-id>"
collectors:
documents:
source: locktivity/epack-collector-documents@^0.1
credentials:
- locktivity_documents
For a pipeline you run yourself, configure the collector with an API
application's client id and client secret. The collector uses them to request an
access token for the run.
collectors:
documents:
source: locktivity/epack-collector-documents@^0.1
config:
pipeline_id: "<pipeline-id>"
secrets:
- LOCKTIVITY_CLIENT_ID
- LOCKTIVITY_CLIENT_SECRET
- LOCKTIVITY_RUN_KEY
- GITHUB_RUN_ID
- GITHUB_RUN_ATTEMPT
Only variables listed under secrets reach the collector.
Run identity groups retries of the same run so they produce the identical set
of documents; without it, every invocation includes the latest documents as a
fresh set.
export LOCKTIVITY_RUN_KEY="$YOUR_CI_RUN_ID"
In GitHub Actions, skip this step: keep GITHUB_RUN_ID and
GITHUB_RUN_ATTEMPT in the secrets list and the collector uses them.
| Option | Required | Description |
|---|---|---|
pipeline_id |
In your own CI | Which pipeline's document selection to include. On a Locktivity-managed pipeline the token already identifies the pipeline, so this is omitted; with client credentials it is required, and Locktivity fills it in when it generates the configuration. |
run_key |
No | Groups retries of the same run. On a Locktivity-managed pipeline this comes from the workflow run's verified identity automatically; in your own CI, export LOCKTIVITY_RUN_KEY per run instead. Set this option directly only for one-off runs outside any CI. |
insecure_endpoint |
No | Advanced HTTPS endpoint override for the documents API. The insecure_ name is an explicit acknowledgement that API traffic is redirected away from the default endpoint. |
insecure_auth_endpoint |
No | Advanced HTTPS endpoint override for the client-credentials token exchange. Use only a trusted endpoint; the collector sends LOCKTIVITY_CLIENT_SECRET there. |
Endpoint overrides redirect API traffic away from the default Locktivity
service. Use them only with endpoints you control or explicitly trust.
Custom endpoint URLs must not include userinfo, query strings, or fragments.
Plain HTTP endpoint overrides are always rejected.
collectors:
documents:
source: locktivity/epack-collector-documents@^0.1
config:
pipeline_id: "<pipeline-id>"
insecure_endpoint: "https://api.example.com"
insecure_auth_endpoint: "https://app.example.com"
secrets:
- LOCKTIVITY_CLIENT_ID
- LOCKTIVITY_CLIENT_SECRET
| Variable | Description |
|---|---|
LOCKTIVITY_DOCUMENTS_TOKEN |
Short-lived token issued per run on managed pipelines. You never set this yourself. |
LOCKTIVITY_CLIENT_ID |
API application client id, for your own CI. |
LOCKTIVITY_CLIENT_SECRET |
API application client secret, for your own CI. |
LOCKTIVITY_RUN_KEY |
Per-run identity exported by your CI, so retries stay identical. |
GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT |
GitHub Actions run identity, used automatically when listed under secrets. |
Your epack is older than v0.2.0. Upgrade it.
The token was missing or rejected. On a managed pipeline, check the pipeline's
Documents credential in Locktivity. In your own CI, check
LOCKTIVITY_CLIENT_ID and LOCKTIVITY_CLIENT_SECRET and the application's
Collect documents permission.
The pipeline in Locktivity doesn't have the Documents collector enabled. Add
it in the pipeline's collectors step.
A downloaded document didn't match what Locktivity recorded. The run fails on
purpose; re-run, and contact support if it persists rather than bypassing the
check.
A document that has no file uploaded yet doesn't fail the run: it's listed in
documents.json with a warning and named in the run summary. Upload a file
for it in Locktivity and the next run includes it.
When you add the Documents collector to a pipeline, Locktivity generates the
workflow and epack.yaml. The generated collector section looks like:
stream: myorg/production
credential_sets:
locktivity_documents: "credset_9f8e7d"
collectors:
documents:
source: locktivity/epack-collector-documents@^0.1
credentials:
- locktivity_documents
That's all that's needed: the pipeline run includes the documents you selected
for it, authenticated with a short-lived token issued for the run.
Outside GitHub Actions, the collector authenticates with an API application's
client credentials and names its pipeline explicitly. Locktivity generates
this configuration for CLI pipelines:
stream: myorg/production
collectors:
documents:
source: locktivity/epack-collector-documents@^0.1
config:
pipeline_id: "pl_9f8e7d"
secrets:
- LOCKTIVITY_CLIENT_ID
- LOCKTIVITY_CLIENT_SECRET
- LOCKTIVITY_RUN_KEY
- GITHUB_RUN_ID
- GITHUB_RUN_ATTEMPT
Then run:
export LOCKTIVITY_CLIENT_ID="..."
export LOCKTIVITY_CLIENT_SECRET="..."
export LOCKTIVITY_RUN_KEY="$YOUR_CI_RUN_ID"
epack collect
The application needs the Collect documents permission. See
Configuration for setup instructions and what each
variable does.
The index at artifacts/documents.json:
{
"snapshot_id": "snap_1a2b3c",
"pipeline_id": "pl_9f8e7d",
"run_key": "gha-1234-1",
"captured_at": "2026-07-08T12:00:00Z",
"digest": "sha256:...",
"documents": [
{
"document_id": "doc_4f2a9c",
"name": "Acme SOC 2 Type II 2025",
"source": "upload",
"version_number": 3,
"document_type": "evidencepack/soc2-report@v1",
"file": {
"path": "artifacts/documents/doc_4f2a9c/acme-soc2-2025.pdf",
"digest": "sha256:...",
"content_type": "application/pdf",
"byte_size": 1048576
},
"text": {
"path": "artifacts/documents/doc_4f2a9c/text.json",
"digest": "sha256:..."
},
"metadata": {
"path": "artifacts/documents/doc_4f2a9c/metadata.json"
},
"warnings": []
}
]
}
# List the documents in a pack
unzip -l evidence-*.epack | grep documents
# See each document's name, type, and where its files landed
unzip -p evidence-*.epack artifacts/documents.json | jq '.documents[] | {name, document_type, file: .file.path, text: .text.path}'
# Read a document's extracted details (auditor, dates, and where each was found)
unzip -p evidence-*.epack artifacts/documents/<id>/metadata.json | jq
**Full Changelog**: https://github.com/locktivity/epack-collector-documents/compare/v0.1.0...v0.1.1
**Full Changelog**: https://github.com/locktivity/epack-collector-documents/commits/v0.1.0