fix: use auths-dev/verify action and SDK-based demo scripts

This commit is contained in:
bordumb 2026-04-05 01:12:42 -07:00
parent adaf2933af
commit 8f236f285f
No known key found for this signature in database
3 changed files with 31 additions and 46 deletions

View file

@ -19,7 +19,7 @@ jobs:
timeout-minutes: 5
permissions:
contents: read
pull-requests: write
pull-requests: ${{ github.event_name == 'pull_request' && 'write' || 'none' }}
steps:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
@ -28,10 +28,10 @@ jobs:
persist-credentials: false
- name: Verify commits with Auths
uses: auths-dev/auths-verify-github-action@57e304ef368d30474e5b6a04106cacde6a8ce492 # v1
uses: auths-dev/verify@v1
with:
allowed-signers: .auths/allowed_signers
token: .auths/allowed_signers
fail-on-unsigned: 'false'
skip-merge-commits: 'true'
post-pr-comment: 'true'
github-token: ${{ secrets.GITHUB_TOKEN }}
post-pr-comment: ${{ github.event_name == 'pull_request' && 'true' || 'false' }}
github-token: ${{ github.event_name == 'pull_request' && secrets.GITHUB_TOKEN || '' }}

View file

@ -15,7 +15,7 @@ package and a verified maintainer identity**.
[Auths](https://github.com/auths-dev/auths) provides Ed25519 signatures bound to
KERI-based decentralized identifiers (DIDs). With Auths:
- Every commit carries a signature from the maintainer's cryptographic identity
- Every commit and artifact carries a signature from the maintainer's cryptographic identity
- The signature is bound to the maintainer's device keychain (not a registry account)
- Stealing PyPI/npm credentials is insufficient without the signing key
- Verification happens locally — no network calls to a central authority
@ -29,20 +29,25 @@ release must trace back to a signed commit by an authorized maintainer. A packag
published without a matching signed commit has no valid attestation chain and would be
flagged by consumers and CI pipelines that verify signatures.
This workflow adds the commit-signing layer. A full deployment would also use
`auths artifact sign` in the release workflow to bind published packages to signed
commits, closing the gap completely.
This workflow adds the commit-signing layer via the
[`auths-dev/verify`](https://github.com/auths-dev/verify) GitHub Action. A full
deployment would also use `auths artifact sign` (via
[`auths-dev/sign`](https://github.com/auths-dev/sign)) in the release workflow to
bind published packages to signed commits.
## Running the Simulation
The simulation script demonstrates the commit-signing layer — it shows that commits
from unauthorized parties are detected:
The simulation script uses the Auths Python SDK to demonstrate the core cryptographic
primitive — it shows that only the holder of the maintainer's private key can produce
a valid signature:
```bash
brew tap auths-dev/auths-cli && brew install auths
pip install auths
python auths_attack_simulation.py
```
No CLI installation, git, or ssh-keygen needed — the script uses the SDK directly.
## Adding Auths to Your Workflow
See the GitHub Actions workflow at `.github/workflows/auths-verify-commits.yml`

View file

@ -22,7 +22,7 @@ How Auths closes this gap:
This simulation uses the Auths Python SDK to demonstrate the core
cryptographic primitive: sign an action with a maintainer's key, then
show that verification succeeds for the legitimate release and fails
for a tampered or unauthorized one.
for an unauthorized or tampered one.
Usage:
pip install auths
@ -41,7 +41,7 @@ def main() -> None:
print()
try:
from auths import sign_action, verify_action_envelope
from auths import generate_inmemory_keypair, sign_action, verify_action_envelope
except ImportError:
print("The 'auths' Python SDK is not installed.")
print()
@ -51,23 +51,9 @@ def main() -> None:
print("Or visit: https://github.com/auths-dev/auths")
sys.exit(0)
# Derive the public key from the private seed for verification.
# In production, the maintainer's public key comes from their Auths
# identity (did:keri:...) and is listed in .auths/allowed_signers.
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
MAINTAINER_SEED_HEX = "a" * 64 # Simulated maintainer private key seed
seed_bytes = bytes.fromhex(MAINTAINER_SEED_HEX)
private_key = Ed25519PrivateKey.from_private_bytes(seed_bytes)
MAINTAINER_PK_HEX = private_key.public_key().public_bytes_raw().hex()
except ImportError:
print("This simulation requires the 'cryptography' package.")
print("Install it with: pip install cryptography")
sys.exit(0)
ATTACKER_SEED_HEX = "b" * 64 # Attacker has a different key
MAINTAINER_DID = "did:keri:EBfxc_LiteLLM_Maintainer"
# Generate ephemeral identities — no filesystem, no keychain needed
maintainer_priv, maintainer_pub, maintainer_did = generate_inmemory_keypair()
attacker_priv, _attacker_pub, attacker_did = generate_inmemory_keypair()
# ── Step 1: Legitimate maintainer signs a release ──────────────────
print("[1] Legitimate maintainer signs release v1.82.6...")
@ -81,20 +67,17 @@ def main() -> None:
})
legitimate_envelope = sign_action(
MAINTAINER_SEED_HEX,
"release",
release_payload,
MAINTAINER_DID,
maintainer_priv, "release", release_payload, maintainer_did,
)
result = verify_action_envelope(legitimate_envelope, MAINTAINER_PK_HEX)
print(f" Signed by: {MAINTAINER_DID}")
result = verify_action_envelope(legitimate_envelope, maintainer_pub)
print(f" Signed by: {maintainer_did}")
print(f" Verification: {'PASSED' if result.valid else 'FAILED'}")
print()
# ── Step 2: Attacker publishes with stolen PyPI token ──────────────
print("[2] Attacker publishes v1.82.7 using stolen PyPI token...")
print(" (Attacker has registry credentials but NOT the signing key)")
print(" (Attacker has registry credentials but NOT the maintainer's signing key)")
print()
malicious_payload = json.dumps({
@ -106,15 +89,12 @@ def main() -> None:
# Attacker signs with their own key — NOT the maintainer's
attacker_envelope = sign_action(
ATTACKER_SEED_HEX,
"release",
malicious_payload,
"did:keri:EATTACKER_unknown_identity",
attacker_priv, "release", malicious_payload, attacker_did,
)
# Verify against the MAINTAINER's public key (the only trusted key)
result = verify_action_envelope(attacker_envelope, MAINTAINER_PK_HEX)
print(f" Signed by: did:keri:EATTACKER_unknown_identity")
result = verify_action_envelope(attacker_envelope, maintainer_pub)
print(f" Signed by: {attacker_did}")
print(f" Verification against maintainer key: {'PASSED' if result.valid else 'FAILED'}")
if result.error:
print(f" Reason: {result.error}")
@ -129,8 +109,8 @@ def main() -> None:
envelope["payload"]["digest"] = "sha256:malicious_payload_hash..."
tampered_json = json.dumps(envelope)
result = verify_action_envelope(tampered_json, MAINTAINER_PK_HEX)
print(f" Original signer: {MAINTAINER_DID}")
result = verify_action_envelope(tampered_json, maintainer_pub)
print(f" Original signer: {maintainer_did}")
print(f" Tampered payload version: 1.82.7")
print(f" Verification: {'PASSED' if result.valid else 'FAILED'}")
if result.error: