Packablock Documentation

Packablock is a deterministic package attestation registry. It generates and verifies cryptographically secured parallel package history chains to defend against software supply chain attacks and package tampering.


📦 Supported Manifests

Packablock natively parses lockfiles and packages to build and audit mathematical trust chains. It currently supports:

  • npm (package-lock.json v1, v2, and v3)
  • Yarn (yarn.lock v1 classic format)
  • Bun (bun.lockb via yarn format, and Bun 1.2+ JSON lockfiles)
  • Ruby Bundler (Gemfile.lock)

🛠️ Installation

Install the Packablock command-line client (pkablk) via the official installation script:

curl -fsSL https://raw.githubusercontent.com/Packablock/packablock-client/dev/scripts/install.sh | sh

🤖 GitHub Actions CI/CD Integration

To guarantee package integrity automatically on every build, run pkablk check inside your GitHub Actions workflows:

name: Deterministic Supply Chain Verification

on:
  push:
    branches: [ main, dev ]
  pull_request:
    branches: [ main ]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Install Packablock Client
        run: curl -fsSL https://raw.githubusercontent.com/Packablock/packablock-client/dev/scripts/install.sh | sh

      - name: Verify Dependency Chain Against Registry
        run: |
          pkablk check packablock.yaml \
            --server https://api.packablock.com \
            --token $

🌐 Verifying Against a Remote Registry

You can check the local chain locally, or anchor-verify it against a remote Packablock Trust Registry server:

pkablk check packablock.yaml --server https://api.packablock.com --token reg_token_123

🚀 Usage

Manage your trust chain using one of the three integration patterns below:

Manage your trust chain dynamically using local commands and verify dependency blocks against a centralized Packablock Trust Registry server.

1. Initialize the Trust Chain

Scan your existing project lockfile to initialize a new genesis block in packablock.yaml:

pkablk init packablock.yaml -l package-lock.json

2. Update Your Dependencies

Install or upgrade packages as you normally would:

npm install lodash@4.17.21

3. Append the Changes to the Chain

Capture the delta between the previous block and the updated lockfile, generating a new cryptographically linked block:

pkablk append packablock.yaml -l package-lock.json

4. Verify Chain Integrity

Ensure no block in the historical chain has been altered or compromised against the remote registry:

pkablk check packablock.yaml --server https://api.packablock.com --token reg_token_123

Store and track your trust chain in an isolated, secure repository branch (e.g. secops/manifest-chain) to prevent developers from directly modifying the manifest files, and run validation gates on your main code branch.

1. Fetch and Checkout the Sentinel Branch Manifest

Retrieve the latest verified trust chain manifest from the isolated branch:

git fetch origin secops/manifest-chain:secops/manifest-chain
git show secops/manifest-chain:packablock.yaml > temp_manifest.yaml

2. Verify Current Lockfile Against Manifest

Ensure your local branch lockfile matches the active Sentinel manifest chain:

pkablk check temp_manifest.yaml --compare-with package-lock.json

3. Append Lockfile Updates

Append the package changes to your temporary manifest local file:

pkablk append temp_manifest.yaml -l package-lock.json

4. Commit and Push Back to Sentinel Branch

Merge the updated trust chain block back into the secure side branch:

git checkout secops/manifest-chain
cp temp_manifest.yaml packablock.yaml
git add packablock.yaml
git commit -m "chore(attestation): append dependency updates to Sentinel chain"
git push origin secops/manifest-chain

Treat your dependency trust chain as a secure OCI artifact and publish it directly to a container registry like GitHub Container Registry (GHCR) to enforce decentralized package trust gates across multiple environments.

1. Authenticate with GitHub Container Registry

Login to GHCR using your secure deployment credentials:

echo ${GITHUB_TOKEN} | oras login ghcr.io -u ${GITHUB_ACTOR} --password-stdin

2. Pull the Latest Trust Chain Artifact

Download the latest verified manifest chain from your GHCR repository:

oras pull ghcr.io/your_github_org/my-repo/manifest-chain:latest

3. Audit Local Lockfile and Append Changes

Audit your local project status against the OCI manifest, and write the updated block:

pkablk check manifest_chain.yaml --compare-with package-lock.json
pkablk append manifest_chain.yaml -l package-lock.json

4. Push the Updated Manifest to GHCR

Publish the new trust chain artifact back to your OCI repository registry:

oras push ghcr.io/your_github_org/my-repo/manifest-chain:latest manifest_chain.yaml:application/yaml

💻 CLI Visualizations & Audit Reports

Running an audit check on your dependencies with the --visualize flag renders a detailed SemVer Candle Chart mapping pinned versions against constraints and upstream releases, highlighting security warnings and policy violations:

bash — pkablk audit
🔍 Packablock Supply Chain Velocity Audit
Target: /home/aaron/dev/my-project
Registry Anchor: https://api.packablock.com
Status: SECURELY ANCHORED (14 Blocks Aligned)

## SemVer Candle Analysis (Lockfile Lifecycle)
Legend:
  | : Min/Max Constraint Boundary   ░ : Historical Drift (First seen -> Pinned)
  ● : Current Pinned Version        ═ : Unused Allowed Range (Upstream Available)
  ► : Extension to Infinity (>=)

### Manifest: package.json
--------------------------------------------------------------------------------
Package Name      Tracked  Constraint  Timeline (Low -> Pinned -> Upstream -> Max)
--------------------------------------------------------------------------------
lodash            Yes      ^4.17.0     |░░░░░════════════════════════════════════|
fastify           Yes      ^4.20.0     |-----░░░════════════════════════════════|
typescript        Yes      >=5.0.0     |-----░░░░░░============================
eslint            No       ^8.40.0     |░░░░░░░░░░░░░══════════════════════════|
--------------------------------------------------------------------------------

Warn:
  Open Fuse (>= Risk): typescript
  Technical Debt Wall: lodash, fastify

Info:
  Fully Up-To-Date: eslint

Tip: Register this log to a Packablock registry to enable automated enterprise security policies and webhook alerts.

🛡️ Policy Control Configuration

Packablock allows organizations to define deterministic security gates to audit dependencies and prevent vulnerability ingestion. Policies are specified in a packablock.policy.yaml configuration file and can be set up at three distinct levels of granularity:

1. 🏢 Organization-Level Policies (Global Gate)

To enforce policies globally across all repositories in the organization, save the policy file within your central .github repository:

[org-profile-repo]/.github/packablock.policy.yaml

The central Packablock Registry automatically ingests this global configuration, applying it as a baseline evaluation gate for all repository logs pushed to the server.

2. 📦 Repository-Level Policies (Project Gate)

To define project-specific rules, place the policy file in a hidden directory at the root of your repository:

[project-repo]/.packablock/policy.yaml

This enables repository administrators to override or supplement global organization policies (e.g., enforcing tighter version drift constraints on sensitive microservices).

3. 📄 Manifest-Specific Policies (Targeted Gate)

Within any policy file, rules can target specific package ecosystems or lockfile manifests by utilizing the selector key:

rules:
  - name: "prevent-npm-infinite-operators"
    level: "error"
    target: "manifest"
    selector:
      manifests: ["package-lock.json"]  # Targets only npm lockfiles
    condition:
      operator_is: [">=", "*"]
      message: "Unbounded version operators (>=, *) are disallowed in Node.js dependencies."

📜 Example Policy Schema (packablock.policy.yaml)

version: "v1"
rules:
  # Block dangerous open-ended SemVer operators
  - name: "no-open-ended-operators"
    level: "error"
    target: "manifest"
    selector:
      ecosystems: ["npm", "bun", "rubygems"]
    condition:
      operator_is: [">=", "*"]
      message: "Open-ended version operators are disallowed under security policy."

  # Flag version drift and technical debt (warn if older than 180 days)
  - name: "version-drift-limit"
    level: "warn"
    target: "package"
    selector:
      manifests: ["package-lock.json", "Gemfile.lock"]
    condition:
      max_drift_days: 180
      message: "Package drift exceeds 6 months threshold."

  # Block pruning history logs
  - name: "never-forget-history"
    level: "error"
    target: "chain"
    condition:
      allow_forget: false
      message: "Deleting or pruning attestation history is blocked."

🤝 Contributing

Packablock is an open-source standard. We welcome specifications feedback, parser improvements, and registry suggestions.

Please read the Call for Community Contributions section in our Continuous Attestation Specification to learn about the current active feedback areas and how you can get involved.


👥 Team

Packablock is created and maintained by: