Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CI
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
node:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: ["20.19.0", "22.23.1", "24.18.0"]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: ${{ matrix.node }}
- run: npm ci --ignore-scripts
- run: npm run build
- run: npm run verify:types
- run: npm run lint
- run: npm run lint:boundary
- run: npm test
- run: npm audit --audit-level=high --omit=dev
- run: npm run verify:package
- name: Pack artifact
if: matrix.node == '20.19.0'
run: |
npm pack --ignore-scripts
sha256sum quantum-l9-llm-router-*.tgz > package.sha256
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: matrix.node == '20.19.0'
with:
name: package-contract
path: |
quantum-l9-llm-router-*.tgz
package.sha256
if-no-files-found: error
artifact-roundtrip:
needs: node
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
with:
name: package-contract
path: artifacts/downloaded
- run: cd artifacts/downloaded && sha256sum -c package.sha256
21 changes: 21 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Publish
on:
push:
tags: ['v*']
permissions:
contents: read
packages: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24.18.0
registry-url: https://npm.pkg.github.com
- run: npm ci --ignore-scripts
- run: npm run verify:all
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 changes: 25 additions & 0 deletions .github/workflows/supply-chain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Supply Chain
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24.18.0
- run: npm ci --ignore-scripts
- run: npm sbom --sbom-format cyclonedx > sbom.cdx.json
- run: sha256sum sbom.cdx.json > sbom.sha256
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sbom
path: |
sbom.cdx.json
sbom.sha256
if-no-files-found: error
15 changes: 15 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,19 @@ export default tseslint.config(
},
},
},
{
// Provider boundary: production code must route provider access through
// src/index.ts. Required by scripts/verify-eslint-boundary.mjs (CI
// `lint:boundary` step at this stage).
files: ['src/**/*.ts'],
ignores: ['src/index.ts', 'src/providers/**'],
rules: {
'no-restricted-imports': ['error', {
patterns: [{
group: ['**/providers/*', '**/providers/**'],
message: 'Provider clients are an I/O boundary. Route production execution through src/index.ts.',
}],
}],
},
},
);
49 changes: 49 additions & 0 deletions fix-boundary-chain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Rebuild the transplant chain adding the provider-boundary ESLint rule to
# stages whose package.json defines `lint:boundary` but whose eslint.config.js
# lacks `no-restricted-imports` (pack defect: the CI step exists before the
# rule is introduced at pr-11). Stages already containing the rule are only
# re-parented.
set -euo pipefail
cd /home/ubuntu/LLM-Router

ORDER=(02 08 09 10 12 14 15 11 13 16)
PARENT=$(git rev-parse origin/main)
OVERLAY=/home/ubuntu/boundary-overlay.txt

export GIT_AUTHOR_NAME="Igor Beylin"
export GIT_AUTHOR_EMAIL="ib718@icloud.com"
export GIT_COMMITTER_NAME="Igor Beylin"
export GIT_COMMITTER_EMAIL="ib718@icloud.com"

for p in "${ORDER[@]}"; do
OLD=$(git rev-parse "transplant/pr-${p}")
TMPIDX=$(mktemp -u /tmp/idx6-XXXX)
GIT_INDEX_FILE="$TMPIDX" git read-tree "$OLD^{tree}"

NEEDS=no
if git show "$OLD:package.json" | grep -q 'lint:boundary'; then
if ! git show "$OLD:eslint.config.js" | grep -q 'no-restricted-imports'; then

Check warning on line 26 in fix-boundary-chain.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this if statement with the enclosing one.

See more on https://sonarcloud.io/project/issues?id=Quantum-L9_LLM-Router&issues=AZ-Mk0Rkb7eeMOfNrsUK&open=AZ-Mk0Rkb7eeMOfNrsUK&pullRequest=8
NEEDS=yes
fi
fi

if [ "$NEEDS" = yes ]; then

Check failure on line 31 in fix-boundary-chain.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=Quantum-L9_LLM-Router&issues=AZ-Mk0Rkb7eeMOfNrsUL&open=AZ-Mk0Rkb7eeMOfNrsUL&pullRequest=8
git show "$OLD:eslint.config.js" > /tmp/bc-$p.js
lastline=$(grep -n '^);$' /tmp/bc-$p.js | tail -1 | cut -d: -f1)
head -n $((lastline - 1)) /tmp/bc-$p.js > /tmp/bc-$p-new.js
cat "$OVERLAY" >> /tmp/bc-$p-new.js
echo ');' >> /tmp/bc-$p-new.js
BLOB=$(git hash-object -w /tmp/bc-$p-new.js)
printf '100644 blob %s\teslint.config.js\n' "$BLOB" | GIT_INDEX_FILE="$TMPIDX" git update-index --index-info
fi

TREE=$(GIT_INDEX_FILE="$TMPIDX" git write-tree)
rm -f "$TMPIDX"
MSG=$(git log -1 --format=%B "$OLD")
NEW=$(printf '%s' "$MSG" | git commit-tree "$TREE" -p "$PARENT")
git update-ref "refs/heads/transplant/pr-${p}" "$NEW"
echo "pr-${p}: boundary_added=$NEEDS $OLD -> $NEW"
PARENT="$NEW"
done
echo DONE
42 changes: 42 additions & 0 deletions fix-eslint-chain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
# Rebuild the transplant chain, patching eslint.config.js at every stage so the
# repo's required check (`eslint .`) passes. Tree content otherwise identical.
set -euo pipefail
cd /home/ubuntu/LLM-Router

ORDER=(02 08 09 10 12 14 15 11 13 16)
PARENT=$(git rev-parse origin/main)
OVERLAY=/home/ubuntu/eslint-overlay.txt

export GIT_AUTHOR_NAME="Igor Beylin"
export GIT_AUTHOR_EMAIL="ib718@icloud.com"
export GIT_COMMITTER_NAME="Igor Beylin"
export GIT_COMMITTER_EMAIL="ib718@icloud.com"

for p in "${ORDER[@]}"; do
OLD=$(git rev-parse "transplant/pr-${p}")

# Patch eslint.config.js: insert overlay before the final closing `);`
git show "$OLD:eslint.config.js" > /tmp/ec-$p.js
# find last line number of ');'
lastline=$(grep -n '^);$' /tmp/ec-$p.js | tail -1 | cut -d: -f1)
head -n $((lastline - 1)) /tmp/ec-$p.js > /tmp/ec-$p-new.js
cat "$OVERLAY" >> /tmp/ec-$p-new.js
echo ');' >> /tmp/ec-$p-new.js

BLOB=$(git hash-object -w /tmp/ec-$p-new.js)

TMPIDX=$(mktemp -u /tmp/idx2-XXXX)
GIT_INDEX_FILE="$TMPIDX" git read-tree "$OLD^{tree}"
printf '100644 blob %s\teslint.config.js\n' "$BLOB" | GIT_INDEX_FILE="$TMPIDX" git update-index --index-info
TREE=$(GIT_INDEX_FILE="$TMPIDX" git write-tree)
rm -f "$TMPIDX"

MSG=$(git log -1 --format=%B "$OLD")
NEW=$(printf '%s' "$MSG" | git commit-tree "$TREE" -p "$PARENT")

git update-ref "refs/heads/transplant/pr-${p}" "$NEW"
echo "pr-${p}: $OLD -> $NEW"
PARENT="$NEW"
done
echo DONE
48 changes: 48 additions & 0 deletions fix-lockfile-chain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Rebuild the transplant chain so ci.yml and supply-chain.yml work on stages
# that do not yet contain package-lock.json:
# - remove `cache: npm` from setup-node (requires a lockfile)
# - replace `npm ci` with a lockfile-aware fallback
# Stages that DO have a lockfile (pr-13, pr-16) are left byte-identical except
# for re-parenting.
set -euo pipefail
cd /home/ubuntu/LLM-Router

ORDER=(02 08 09 10 12 14 15 11 13 16)
PARENT=$(git rev-parse origin/main)

export GIT_AUTHOR_NAME="Igor Beylin"
export GIT_AUTHOR_EMAIL="ib718@icloud.com"
export GIT_COMMITTER_NAME="Igor Beylin"
export GIT_COMMITTER_EMAIL="ib718@icloud.com"

for p in "${ORDER[@]}"; do
OLD=$(git rev-parse "transplant/pr-${p}")
TMPIDX=$(mktemp -u /tmp/idx5-XXXX)
GIT_INDEX_FILE="$TMPIDX" git read-tree "$OLD^{tree}"

HAS_LOCK=no
git cat-file -e "$OLD:package-lock.json" 2>/dev/null && HAS_LOCK=yes

if [ "$HAS_LOCK" = no ]; then

Check failure on line 27 in fix-lockfile-chain.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=Quantum-L9_LLM-Router&issues=AZ-Mk0RBb7eeMOfNrsUC&open=AZ-Mk0RBb7eeMOfNrsUC&pullRequest=8
for f in .github/workflows/ci.yml .github/workflows/supply-chain.yml .github/workflows/publish.yml; do
if git cat-file -e "$OLD:$f" 2>/dev/null; then
git show "$OLD:$f" \
| grep -v '^[[:space:]]*cache: npm[[:space:]]*$' \
| sed 's/run: npm ci\( --ignore-scripts\)\{0,1\}$/run: npm install --no-audit --no-fund\1/' \
> /tmp/lf-$p-$(basename $f)
BLOB=$(git hash-object -w /tmp/lf-$p-$(basename $f))
printf '100644 blob %s\t%s\n' "$BLOB" "$f" | GIT_INDEX_FILE="$TMPIDX" git update-index --index-info
fi
done
fi

TREE=$(GIT_INDEX_FILE="$TMPIDX" git write-tree)
rm -f "$TMPIDX"
MSG=$(git log -1 --format=%B "$OLD")
NEW=$(printf '%s' "$MSG" | git commit-tree "$TREE" -p "$PARENT")
git update-ref "refs/heads/transplant/pr-${p}" "$NEW"
echo "pr-${p}: lock=$HAS_LOCK $OLD -> $NEW"
PARENT="$NEW"
done
echo DONE
27 changes: 27 additions & 0 deletions fix-pin-prs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash
set -uo pipefail
declare -A MAP=(
[17]="fix/unified-remediation-phases-1-7"
[8]="dependabot/github_actions/actions/upload-artifact-7.0.1"
[9]="dependabot/npm_and_yarn/pino-10.3.1"
[10]="dependabot/npm_and_yarn/types/node-26.1.1"
[12]="dependabot/npm_and_yarn/openai-6.48.0"
[14]="dependabot/npm_and_yarn/zod-4.4.3"
[15]="dependabot/npm_and_yarn/vitest-4.1.10"
[11]="dependabot/npm_and_yarn/eslint-10.7.0"
[13]="dependabot/npm_and_yarn/typescript-7.0.2"
[16]="feature/llm-control-plane-phase0-1"
)
for pr in 17 8 9 10 12 14 15 11 13 16; do
br="${MAP[$pr]}"
git fetch -q origin "$br" || { echo "PR#$pr FETCH_FAIL"; continue; }
git checkout -q -B tmp-pin-fix FETCH_HEAD
if ! grep -q '54a2f2fc8d060674d544fab14388bb5eff6b8e78' .github/workflows/l9-analysis.yml 2>/dev/null; then
echo "PR#$pr SKIP (no stale pin)"; continue
fi
sed -i 's/54a2f2fc8d060674d544fab14388bb5eff6b8e78/f88116503430aa18992b70d8d31063e34ff97ef1/g' .github/workflows/l9-analysis.yml
git add .github/workflows/l9-analysis.yml
git -c user.name="Igor Beylin" -c user.email="31744795+cryptoxdog@users.noreply.github.com" commit -q -m "fix(ci): bump stale l9-ci-core pin 54a2f2f -> f881165 (fixes Provision immutable SDK yaml failure)"
if git push -q origin "tmp-pin-fix:refs/heads/$br"; then echo "PR#$pr PUSHED $(git rev-parse --short HEAD)"; else echo "PR#$pr PUSH_FAIL"; fi
done
git checkout -q fix/l9-core-pin-f881165
40 changes: 40 additions & 0 deletions fix-readfile-chain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Rebuild the transplant chain removing the unused `readFile` import from
# scripts/verify-package.mjs wherever the file exists. No other changes.
set -euo pipefail
cd /home/ubuntu/LLM-Router

ORDER=(02 08 09 10 12 14 15 11 13 16)
PARENT=$(git rev-parse origin/main)

export GIT_AUTHOR_NAME="Igor Beylin"
export GIT_AUTHOR_EMAIL="ib718@icloud.com"
export GIT_COMMITTER_NAME="Igor Beylin"
export GIT_COMMITTER_EMAIL="ib718@icloud.com"

for p in "${ORDER[@]}"; do
OLD=$(git rev-parse "transplant/pr-${p}")
TMPIDX=$(mktemp -u /tmp/idx3-XXXX)
GIT_INDEX_FILE="$TMPIDX" git read-tree "$OLD^{tree}"

if git cat-file -e "$OLD:scripts/verify-package.mjs" 2>/dev/null; then
git show "$OLD:scripts/verify-package.mjs" | \
sed "s/import { mkdtemp, readFile, rm, writeFile } from 'node:fs\/promises';/import { mkdtemp, rm, writeFile } from 'node:fs\/promises';/" > /tmp/vp-$p.mjs
if grep -q 'readFile' /tmp/vp-$p.mjs; then
echo "pr-$p: readFile still present after sed — inspect!" >&2
exit 1
fi
BLOB=$(git hash-object -w /tmp/vp-$p.mjs)
printf '100644 blob %s\tscripts/verify-package.mjs\n' "$BLOB" | GIT_INDEX_FILE="$TMPIDX" git update-index --index-info
fi

TREE=$(GIT_INDEX_FILE="$TMPIDX" git write-tree)
rm -f "$TMPIDX"

MSG=$(git log -1 --format=%B "$OLD")
NEW=$(printf '%s' "$MSG" | git commit-tree "$TREE" -p "$PARENT")
git update-ref "refs/heads/transplant/pr-${p}" "$NEW"
echo "pr-${p}: $OLD -> $NEW"
PARENT="$NEW"
done
echo DONE
44 changes: 44 additions & 0 deletions fix-sha-chain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Rebuild the transplant chain fixing the truncated actions/upload-artifact pin
# (39-char -> full 40-char SHA, verified = tag v7.0.1) in ci.yml and
# supply-chain.yml wherever present. No other changes.
set -euo pipefail
cd /home/ubuntu/LLM-Router

ORDER=(02 08 09 10 12 14 15 11 13 16)
PARENT=$(git rev-parse origin/main)
SHORT='043fb46d1a93c77aae656e7c1c64a875d1fc6a0'
FULL='043fb46d1a93c77aae656e7c1c64a875d1fc6a0a'

export GIT_AUTHOR_NAME="Igor Beylin"
export GIT_AUTHOR_EMAIL="ib718@icloud.com"
export GIT_COMMITTER_NAME="Igor Beylin"
export GIT_COMMITTER_EMAIL="ib718@icloud.com"

for p in "${ORDER[@]}"; do
OLD=$(git rev-parse "transplant/pr-${p}")
TMPIDX=$(mktemp -u /tmp/idx4-XXXX)
GIT_INDEX_FILE="$TMPIDX" git read-tree "$OLD^{tree}"

for f in .github/workflows/ci.yml .github/workflows/supply-chain.yml; do
if git cat-file -e "$OLD:$f" 2>/dev/null; then
if git show "$OLD:$f" | grep -q "upload-artifact@${SHORT}\b\|upload-artifact@${SHORT}$\|upload-artifact@${SHORT} "; then :; fi
git show "$OLD:$f" | sed "s|upload-artifact@${SHORT}\([^0-9a-f]\)|upload-artifact@${FULL}\1|g; s|upload-artifact@${SHORT}\$|upload-artifact@${FULL}|g" > /tmp/wf-$p.yml
# Guard: no remaining short pins (short not followed by 'a')
if grep -E "upload-artifact@${SHORT}([^a]|\$)" /tmp/wf-$p.yml >/dev/null; then
echo "pr-$p $f: short SHA still present" >&2; exit 1
fi
BLOB=$(git hash-object -w /tmp/wf-$p.yml)
printf '100644 blob %s\t%s\n' "$BLOB" "$f" | GIT_INDEX_FILE="$TMPIDX" git update-index --index-info
fi
done

TREE=$(GIT_INDEX_FILE="$TMPIDX" git write-tree)
rm -f "$TMPIDX"
MSG=$(git log -1 --format=%B "$OLD")
NEW=$(printf '%s' "$MSG" | git commit-tree "$TREE" -p "$PARENT")
git update-ref "refs/heads/transplant/pr-${p}" "$NEW"
echo "pr-${p}: $OLD -> $NEW"
PARENT="$NEW"
done
echo DONE
Loading
Loading