Skip to content

Commit 199413f

Browse files
Expand to test all PyPI token capabilities: auth, upload, yank routes
1 parent 6fdf663 commit 199413f

1 file changed

Lines changed: 91 additions & 16 deletions

File tree

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Test PyPI yank capability
1+
name: Test PyPI token capabilities
22

33
on:
44
workflow_dispatch:
@@ -7,27 +7,102 @@ on:
77
- test-pypi-yank
88

99
jobs:
10-
test-yank:
10+
test-capabilities:
1111
runs-on: ubuntu-latest
12+
env:
13+
PYPI_TOKEN: ${{ secrets.PYPI }}
1214
steps:
13-
- name: Install twine
14-
run: pip install twine
15+
- name: Install dependencies
16+
run: pip install twine requests
1517

16-
- name: Attempt to yank policyengine-uk 0.35.0
17-
env:
18-
PYPI_TOKEN: ${{ secrets.PYPI }}
18+
- name: "Test 1: Verify token is valid (check auth via upload endpoint)"
1919
run: |
20-
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
21-
-X POST "https://pypi.org/pypi/policyengine-uk/0.35.0/yank" \
22-
-H "Authorization: Bearer $PYPI_TOKEN" \
23-
-d "reason=Test%3A+verifying+org+secret+has+yank+permissions")
24-
echo "HTTP status: $STATUS"
20+
# POST with no files - a valid token gets 400 (bad request, missing file)
21+
# an invalid token gets 403
22+
STATUS=$(curl -s -o /tmp/auth_test.txt -w "%{http_code}" \
23+
-X POST "https://upload.pypi.org/legacy/" \
24+
-u "__token__:$PYPI_TOKEN")
25+
echo "Auth check status: $STATUS"
26+
cat /tmp/auth_test.txt
27+
if [ "$STATUS" = "400" ]; then
28+
echo "RESULT: Token authenticated OK (400 = auth passed, bad request)"
29+
elif [ "$STATUS" = "403" ]; then
30+
echo "RESULT: Token REJECTED (403 = wrong token or no permission)"
31+
else
32+
echo "RESULT: Unexpected status $STATUS"
33+
fi
34+
35+
- name: "Test 2: Attempt upload of a dummy/existing version (tests publish scope)"
36+
run: |
37+
# We'll try uploading a fake dist — if token has upload scope we get 400 (bad file)
38+
# If token is read-only we get 403
39+
echo "dummy" > /tmp/fake.tar.gz
40+
STATUS=$(curl -s -o /tmp/upload_test.txt -w "%{http_code}" \
41+
-X POST "https://upload.pypi.org/legacy/" \
42+
-u "__token__:$PYPI_TOKEN" \
43+
-F ":action=file_upload" \
44+
-F "protocol_version=1" \
45+
-F "name=policyengine-uk" \
46+
-F "version=0.35.0" \
47+
-F "filetype=sdist" \
48+
-F "pyversion=source" \
49+
-F "content=@/tmp/fake.tar.gz;type=application/octet-stream")
50+
echo "Upload test status: $STATUS"
51+
cat /tmp/upload_test.txt
52+
if [ "$STATUS" = "400" ]; then
53+
echo "RESULT: Token has upload permission (400 = auth OK, file invalid)"
54+
elif [ "$STATUS" = "403" ]; then
55+
echo "RESULT: Token LACKS upload permission (403)"
56+
fi
57+
58+
- name: "Test 3: Attempt yank via warehouse internal route"
59+
run: |
60+
# PyPI warehouse exposes a CSRF-protected manage route; tokens don't work here
61+
# but we test to confirm the response
62+
STATUS=$(curl -s -o /tmp/yank_test.txt -w "%{http_code}" \
63+
-X POST "https://pypi.org/manage/project/policyengine-uk/release/0.35.0/yank/" \
64+
-H "Authorization: token $PYPI_TOKEN" \
65+
-H "Content-Type: application/x-www-form-urlencoded" \
66+
-d "yanked_reason=test")
67+
echo "Yank attempt status: $STATUS"
68+
cat /tmp/yank_test.txt | python3 -c "import sys; content=sys.stdin.read(); print(content[:300])"
2569
if [ "$STATUS" = "200" ]; then
26-
echo "YANK SUCCEEDED - token has yank permissions"
70+
echo "RESULT: YANK SUCCEEDED"
71+
elif [ "$STATUS" = "302" ]; then
72+
echo "RESULT: Redirect (may have worked or redirected to login)"
2773
elif [ "$STATUS" = "403" ]; then
28-
echo "YANK FAILED 403 - token lacks permission or wrong scope"
74+
echo "RESULT: Forbidden - token not accepted for yank"
2975
elif [ "$STATUS" = "401" ]; then
30-
echo "YANK FAILED 401 - token authentication failed"
76+
echo "RESULT: Unauthorized - token rejected"
3177
else
32-
echo "YANK FAILED with unexpected status $STATUS"
78+
echo "RESULT: Status $STATUS - token likely not accepted for web management routes"
3379
fi
80+
81+
- name: "Test 4: Attempt yank via upload.pypi.org with :action=yank"
82+
run: |
83+
STATUS=$(curl -s -o /tmp/yank2_test.txt -w "%{http_code}" \
84+
-X POST "https://upload.pypi.org/legacy/" \
85+
-u "__token__:$PYPI_TOKEN" \
86+
-F ":action=yank" \
87+
-F "name=policyengine-uk" \
88+
-F "version=0.35.0" \
89+
-F "yanked_reason=test+yank+capability")
90+
echo "Yank via upload endpoint status: $STATUS"
91+
cat /tmp/yank2_test.txt | python3 -c "import sys; content=sys.stdin.read(); print(content[:300])"
92+
if [ "$STATUS" = "200" ]; then
93+
echo "RESULT: YANK SUCCEEDED via upload endpoint"
94+
elif [ "$STATUS" = "400" ]; then
95+
echo "RESULT: Auth OK but action not supported (400)"
96+
elif [ "$STATUS" = "403" ]; then
97+
echo "RESULT: Forbidden"
98+
else
99+
echo "RESULT: Status $STATUS"
100+
fi
101+
102+
- name: Summary
103+
run: |
104+
echo "=============================="
105+
echo "Test summary:"
106+
echo "See individual steps above for RESULT lines."
107+
echo "Token prefix (first 10 chars):"
108+
echo "$PYPI_TOKEN" | cut -c1-15

0 commit comments

Comments
 (0)