mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
fix: use auths-dev/verify action and SDK-based demo scripts
This commit is contained in:
parent
adaf2933af
commit
8f236f285f
3 changed files with 31 additions and 46 deletions
10
.github/workflows/auths-verify-commits.yml
vendored
10
.github/workflows/auths-verify-commits.yml
vendored
|
|
@ -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 || '' }}
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue