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
10 changes: 5 additions & 5 deletions .github/workflows/daily-agentrx-trace-optimizer.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion .github/workflows/daily-agentrx-trace-optimizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ steps:
git -C "$AGENTRX_HOME/src" fetch --depth 1 origin 7a18c79708e7671be15124460f4f7296107c2a55
git -C "$AGENTRX_HOME/src" checkout --detach FETCH_HEAD
uv venv --python 3.12 --python-preference only-managed "$AGENTRX_HOME/.venv"
uv pip install --python "$AGENTRX_HOME/.venv/bin/python" "$AGENTRX_HOME/src"
# run.py imports AgentRx from the pinned checkout directly. Sync its complete
# dependency lock without executing a source build or resolving new versions.
uv pip sync --require-hashes --only-binary=:all: --python "$AGENTRX_HOME/.venv/bin/python" "${GITHUB_WORKSPACE}/.github/workflows/requirements-agentrx.txt"
"$AGENTRX_HOME/.venv/bin/python" "$AGENTRX_HOME/src/run.py" --help >/dev/null
safe-outputs:
mentions: false
Expand Down
110 changes: 110 additions & 0 deletions .github/workflows/requirements-agentrx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# AgentRx 7a18c79708e7671be15124460f4f7296107c2a55 runtime dependencies.
# Linux x86_64 / CPython 3.12 wheels only; no source builds.
# Refresh from the pinned checkout's requirements.txt:
# uv pip compile requirements.txt --python-version 3.12 --python-platform x86_64-manylinux_2_28 --only-binary=:all: -o requirements-pinned.txt
# python -m pip download --no-deps --only-binary=:all: --python-version 3.12 --implementation cp --abi cp312 --platform manylinux_2_28_x86_64 --platform manylinux2014_x86_64 --dest wheels -r requirements-pinned.txt
# python -m pip hash wheels/*.whl
aiohappyeyeballs==2.7.1 \
--hash=sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472
aiohttp==3.14.5 \
--hash=sha256:20f085697d7e911f1f73c43ed03fafbed1e7121797e2eb5428efa80398060584
aiosignal==1.4.0 \
--hash=sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e
annotated-types==0.8.0 \
--hash=sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0
anyio==4.15.1 \
--hash=sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101
attrs==26.1.0 \
--hash=sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309
azure-ai-inference==1.0.0b9 \
--hash=sha256:49823732e674092dad83bb8b0d1b65aa73111fab924d61349eb2a8cdc0493990
azure-core==1.41.0 \
--hash=sha256:522b4011e8180b1a3dcd2024396a4e7fe9ac37fb8597db47163d230b5efe892d
azure-identity==1.26.0 \
--hash=sha256:3c60d9682b3ac01507388d474cb5a5ffbe54152a96b6cdcaa7013da9315cf186
certifi==2026.10.19 \
--hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
cffi==2.1.1 \
--hash=sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf
charset-normalizer==3.5.2 \
--hash=sha256:3d31298449090ab8d47b7b1b2a555ff73cac7ed438a08b7ac160980c7ebed649
contourpy==1.4.0 \
--hash=sha256:875f42444c9cf48d56f724f2637e60d0f73b3b12c9041e1484580a233edf9591
cryptography==50.0.2 \
--hash=sha256:4061c0079120205fb760c58acab6443e217307dcf05e3702cf970e0689972856
cycler==0.12.1 \
--hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30
fonttools==4.66.1 \
--hash=sha256:7b8ff9e0edbcee2fbf7dff0c41b9041c1901c26acf64e23adb67495012df11de
frozenlist==1.8.0 \
--hash=sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383
h11==0.16.0 \
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
httpcore2==2.13.1 \
--hash=sha256:e1e05d4f25f7d7d496bfb96748f6f4b67657b03da069b3a68c36069f3db73d0a
httpx2==2.13.1 \
--hash=sha256:6dff50fabc270ee5fd25d845d0b078ed20564579744d6d962850975996d2f9a4
idna==3.20 \
--hash=sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c
iniconfig==2.3.1 \
--hash=sha256:9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7
isodate==0.7.2 \
--hash=sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15
jiter==0.17.0 \
--hash=sha256:8c21265b251d99bbb40080d178a8953e35601d3a1564e05c4de4c0d2ca616797
kiwisolver==1.5.1 \
--hash=sha256:34633ecf50d16187ab8e5528b7a2530f2feb4e23f300db4672538b51cfc5cd38
matplotlib==3.11.2 \
--hash=sha256:df4f7784aca81a94f254c0a2767d592ee25f407e488f5fa7203e51093fb6ca27
msal==1.39.0 \
--hash=sha256:2d2577886906cd7293850dffa2da29119966c213bfc6ec0cecf8bf7621e1ca77
msal-extensions==1.3.1 \
--hash=sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca
multidict==7.1.0 \
--hash=sha256:fed6b7705d49dd07e5e0dd5f5c873fc44047e92d714299b13245b5fecac49d01
numpy==2.5.4 \
--hash=sha256:fbde6962867ee75b48b0ee29b2b9372ec5d617799dbaf38e82dc0596f2f7738a
openai==3.31.0 \
--hash=sha256:e5839f6670483f368de40ce3422f524c1afaf12ff8660539f53489e200db8d78
packaging==26.3 \
--hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c
pillow==12.3.0 \
--hash=sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91
pluggy==1.6.0 \
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
propcache==0.5.4 \
--hash=sha256:2814ecd8e818f487bee4b0f921bc4d1c176cc5fc71ac0f072d0fa67eda4ac14b
pycparser==3.11 \
--hash=sha256:51d5a8ba2be0bbe440b99d2112604c95bbbc3c2748a64260186c541e1729cd80
pydantic==2.14.1 \
--hash=sha256:9195d967ec791692a04438115466764fb8b9a27b31f14a760437694f40d6b454
pydantic-core==2.50.1 \
--hash=sha256:93ba4e9d8210d941c200431a56b2c0400b131865947903937ed3ec5404307d2e
pygments==2.21.0 \
--hash=sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9
pyjwt==2.15.1 \
--hash=sha256:42d59d631f7768a1028a64c7ff581a9bf7519804daf91fc5b6c56e30eec5e193
pyparsing==3.3.3 \
--hash=sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4
pytest==9.1.1 \
--hash=sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c
python-dateutil==2.9.0.post0 \
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
python-dotenv==1.2.4 \
--hash=sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc
requests==2.34.2 \
--hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0
six==1.17.0 \
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274
sniffio==1.3.1 \
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2
truststore==0.10.5 \
--hash=sha256:9aaaedaefaf06d8b206278cf8b5012bc897f485a874503501e12d776df78951c
typing-extensions==4.16.0 \
--hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8
typing-inspection==0.4.4 \
--hash=sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147
urllib3==2.8.0 \
--hash=sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3
yarl==1.25.1 \
--hash=sha256:c6f117789d22dce188e5754e8bc65b7e6ebf8cb73963b9fa761f672a5883769d
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ test-inline-*.lock.yml
*.txt
!docs/public/robots.txt
!docs/public/.well-known/ai.txt
!.github/workflows/requirements-agentrx.txt
conclusion/
detection/

Expand Down
78 changes: 78 additions & 0 deletions pkg/workflow/agentrx_workflow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//go:build !integration

package workflow

import (
"os"
"regexp"
"strings"
"testing"

"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestAgentRxSetupUsesHashedDependencyLock(t *testing.T) {
source, err := os.ReadFile("../../.github/workflows/daily-agentrx-trace-optimizer.md")
require.NoError(t, err)
parts := strings.SplitN(string(source), "---", 3)
require.Len(t, parts, 3)
var frontmatter struct {
Steps []struct {
Name string `yaml:"name"`
Run string `yaml:"run"`
} `yaml:"steps"`
}
require.NoError(t, yaml.Unmarshal([]byte(parts[1]), &frontmatter))
require.NotEmpty(t, frontmatter.Steps)
setup := frontmatter.Steps[0].Run
require.Contains(t, setup, `uv pip sync --require-hashes --only-binary=:all: --python "$AGENTRX_HOME/.venv/bin/python" "${GITHUB_WORKSPACE}/.github/workflows/requirements-agentrx.txt"`)
require.NotContains(t, setup, "uv pip install", "installing the source project dynamically resolves build and runtime dependencies")
require.Contains(t, setup, `"$AGENTRX_HOME/.venv/bin/python" "$AGENTRX_HOME/src/run.py" --help`)

compiled, err := os.ReadFile("../../.github/workflows/daily-agentrx-trace-optimizer.lock.yml")
require.NoError(t, err)
var workflow struct {
Jobs map[string]struct {
Steps []struct {
Name string `yaml:"name"`
Run string `yaml:"run"`
} `yaml:"steps"`
} `yaml:"jobs"`
}
require.NoError(t, yaml.Unmarshal(compiled, &workflow))
var compiledSetup string
for _, step := range workflow.Jobs["agent"].Steps {
if step.Name == frontmatter.Steps[0].Name {
compiledSetup = step.Run
}
}
require.Equal(t, strings.TrimSpace(setup), compiledSetup, "the emitted workflow must preserve the hash-enforced setup")

lock, err := os.ReadFile("../../.github/workflows/requirements-agentrx.txt")
require.NoError(t, err)
revision := regexp.MustCompile(`fetch --depth 1 origin ([0-9a-f]{40})`).FindStringSubmatch(setup)
require.Len(t, revision, 2, "AgentRx source must remain pinned to an immutable commit")
require.Contains(t, string(lock), "# AgentRx "+revision[1]+" runtime dependencies.")

entry := regexp.MustCompile(`^[a-z0-9][a-z0-9.-]*==[0-9][a-zA-Z0-9.]* \\\n --hash=sha256:[0-9a-f]{64}$`)
var requirement strings.Builder
count := 0
for line := range strings.SplitSeq(string(lock), "\n") {
if strings.HasPrefix(line, "#") || strings.TrimSpace(line) == "" {
continue
}
if requirement.Len() > 0 {
requirement.WriteByte('\n')
}
requirement.WriteString(line)
if strings.HasSuffix(line, `\`) {
continue
}
require.Regexp(t, entry, requirement.String(), "every dependency must have an exact version and a SHA-256 wheel hash")
requirement.Reset()
count++
}
require.Zero(t, requirement.Len(), "dependency entries must not be truncated")
require.Positive(t, count)
}
Loading