http-api-tool 1.0.0__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/build-test-release.yaml +260 -8
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/build-test.yaml +140 -12
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/dependencies.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/documentation.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/openssf-scorecard.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/release-drafter.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/security-scans.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/semantic-pull-request.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/verify-gha-versions.yaml +1 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.gitignore +1 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.pre-commit-config.yaml +15 -9
- http_api_tool-1.0.2/CHANGELOG-v0.2.0.md +296 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/Dockerfile +11 -2
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/Makefile +8 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/PKG-INFO +131 -5
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/README.md +129 -4
- http_api_tool-1.0.2/action.yaml +302 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/pyproject.toml +29 -2
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/scripts/generate_requirements.py +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/__init__.py +1 -1
- http_api_tool-1.0.2/src/http_api_tool/_version.py +34 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/cli.py +27 -1
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/uv.lock +1 -95
- http_api_tool-1.0.0/action.yaml +0 -157
- http_api_tool-1.0.0/scripts/README.md +0 -168
- http_api_tool-1.0.0/scripts/requirements_header.txt +0 -2
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.actrc +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.codespell +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.dockerignore +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.editorconfig +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/cache-config.yaml +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/dependabot.yml +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/release-drafter.yml +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/codeql.yml +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.gitlint +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.readthedocs.yml +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.yamllint +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/LICENSE +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/LICENSES/Apache-2.0.txt +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/REUSE.toml +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/UV-QUICK-REFERENCE.md +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/scripts/check-pip-security.py +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/sonar-project.properties +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/__main__.py +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/verifier.py +0 -0
- {http_api_tool-1.0.0 → http_api_tool-1.0.2}/tests/test_http_api_tool.py +0 -0
|
@@ -18,6 +18,10 @@ concurrency:
|
|
|
18
18
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
19
19
|
cancel-in-progress: true
|
|
20
20
|
|
|
21
|
+
env:
|
|
22
|
+
REGISTRY: ghcr.io
|
|
23
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
24
|
+
|
|
21
25
|
jobs:
|
|
22
26
|
tag-validate:
|
|
23
27
|
name: 'Validate Tag Push'
|
|
@@ -29,7 +33,7 @@ jobs:
|
|
|
29
33
|
tag: "${{ steps.tag-validate.outputs.tag }}"
|
|
30
34
|
steps:
|
|
31
35
|
# Harden the runner used by this workflow
|
|
32
|
-
- uses: step-security/harden-runner@
|
|
36
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
33
37
|
with:
|
|
34
38
|
egress-policy: 'audit'
|
|
35
39
|
|
|
@@ -57,7 +61,7 @@ jobs:
|
|
|
57
61
|
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
58
62
|
steps:
|
|
59
63
|
# Harden the runner used by this workflow
|
|
60
|
-
- uses: step-security/harden-runner@
|
|
64
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
61
65
|
with:
|
|
62
66
|
egress-policy: 'audit'
|
|
63
67
|
|
|
@@ -107,7 +111,7 @@ jobs:
|
|
|
107
111
|
timeout-minutes: 12
|
|
108
112
|
steps:
|
|
109
113
|
# Harden the runner used by this workflow
|
|
110
|
-
- uses: step-security/harden-runner@
|
|
114
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
111
115
|
with:
|
|
112
116
|
egress-policy: 'audit'
|
|
113
117
|
|
|
@@ -131,6 +135,7 @@ jobs:
|
|
|
131
135
|
~/.cache/pdm
|
|
132
136
|
.pdm-python
|
|
133
137
|
.venv
|
|
138
|
+
# yamllint disable-line rule:line-length
|
|
134
139
|
key: pdm-release-test-${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'pdm.lock') }}
|
|
135
140
|
restore-keys: |
|
|
136
141
|
pdm-release-test-${{ runner.os }}-python-${{ matrix.python-version }}-
|
|
@@ -155,7 +160,7 @@ jobs:
|
|
|
155
160
|
timeout-minutes: 10
|
|
156
161
|
steps:
|
|
157
162
|
# Harden the runner used by this workflow
|
|
158
|
-
- uses: step-security/harden-runner@
|
|
163
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
159
164
|
with:
|
|
160
165
|
egress-policy: 'audit'
|
|
161
166
|
|
|
@@ -179,6 +184,7 @@ jobs:
|
|
|
179
184
|
~/.cache/pdm
|
|
180
185
|
.pdm-python
|
|
181
186
|
.venv
|
|
187
|
+
# yamllint disable-line rule:line-length
|
|
182
188
|
key: pdm-release-audit-${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'pdm.lock') }}
|
|
183
189
|
restore-keys: |
|
|
184
190
|
pdm-release-audit-${{ runner.os }}-python-${{ matrix.python-version }}-
|
|
@@ -205,7 +211,7 @@ jobs:
|
|
|
205
211
|
timeout-minutes: 5
|
|
206
212
|
steps:
|
|
207
213
|
# Harden the runner used by this workflow
|
|
208
|
-
- uses: step-security/harden-runner@
|
|
214
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
209
215
|
with:
|
|
210
216
|
egress-policy: 'audit'
|
|
211
217
|
|
|
@@ -228,6 +234,80 @@ jobs:
|
|
|
228
234
|
environment: 'development'
|
|
229
235
|
tag: "${{ needs.tag-validate.outputs.tag }}"
|
|
230
236
|
|
|
237
|
+
docker-publish:
|
|
238
|
+
name: 'Publish Docker Image'
|
|
239
|
+
runs-on: 'ubuntu-latest'
|
|
240
|
+
needs:
|
|
241
|
+
- 'tag-validate'
|
|
242
|
+
- 'test-pypi'
|
|
243
|
+
timeout-minutes: 15
|
|
244
|
+
permissions:
|
|
245
|
+
contents: read
|
|
246
|
+
packages: write
|
|
247
|
+
steps:
|
|
248
|
+
# Harden the runner used by this workflow
|
|
249
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
250
|
+
with:
|
|
251
|
+
egress-policy: 'audit'
|
|
252
|
+
|
|
253
|
+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
254
|
+
|
|
255
|
+
# Set up Docker Buildx
|
|
256
|
+
- name: Set up Docker Buildx
|
|
257
|
+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
|
258
|
+
|
|
259
|
+
# Login to GitHub Container Registry
|
|
260
|
+
- name: Login to Container Registry
|
|
261
|
+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
|
262
|
+
with:
|
|
263
|
+
registry: ${{ env.REGISTRY }}
|
|
264
|
+
username: ${{ github.actor }}
|
|
265
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
266
|
+
|
|
267
|
+
# Extract metadata for tags and labels
|
|
268
|
+
- name: Extract metadata
|
|
269
|
+
id: meta
|
|
270
|
+
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
|
|
271
|
+
with:
|
|
272
|
+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
273
|
+
tags: |
|
|
274
|
+
type=semver,pattern={{version}},value=${{ needs.tag-validate.outputs.tag }}
|
|
275
|
+
type=semver,pattern={{major}}.{{minor}},value=${{ needs.tag-validate.outputs.tag }}
|
|
276
|
+
type=semver,pattern={{major}},value=${{ needs.tag-validate.outputs.tag }}
|
|
277
|
+
type=raw,value=latest
|
|
278
|
+
labels: |
|
|
279
|
+
org.opencontainers.image.title=HTTP API Tool
|
|
280
|
+
org.opencontainers.image.description=A Python HTTP/HTTPS API testing tool for GitHub Actions and CLI usage
|
|
281
|
+
org.opencontainers.image.vendor=The Linux Foundation
|
|
282
|
+
org.opencontainers.image.version=${{ needs.tag-validate.outputs.tag }}
|
|
283
|
+
|
|
284
|
+
# Build and push image with comprehensive caching
|
|
285
|
+
- name: Build and push Docker image
|
|
286
|
+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
|
287
|
+
with:
|
|
288
|
+
context: .
|
|
289
|
+
file: ./Dockerfile
|
|
290
|
+
platforms: linux/amd64,linux/arm64
|
|
291
|
+
push: true
|
|
292
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
293
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
294
|
+
build-args: |
|
|
295
|
+
VERSION=${{ needs.tag-validate.outputs.tag }}
|
|
296
|
+
cache-from: |
|
|
297
|
+
type=gha,scope=docker-release
|
|
298
|
+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-base
|
|
299
|
+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-deps
|
|
300
|
+
cache-to: |
|
|
301
|
+
type=gha,mode=max,scope=docker-release
|
|
302
|
+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-base,mode=max
|
|
303
|
+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-deps,mode=max
|
|
304
|
+
|
|
305
|
+
- name: Verify published image
|
|
306
|
+
run: |
|
|
307
|
+
echo "✅ Docker image published successfully to GHCR"
|
|
308
|
+
echo "📦 Version: ${{ needs.tag-validate.outputs.tag }}"
|
|
309
|
+
echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}"
|
|
310
|
+
|
|
231
311
|
pypi:
|
|
232
312
|
name: 'Release PyPI Package'
|
|
233
313
|
runs-on: 'ubuntu-latest'
|
|
@@ -242,7 +322,7 @@ jobs:
|
|
|
242
322
|
timeout-minutes: 5
|
|
243
323
|
steps:
|
|
244
324
|
# Harden the runner used by this workflow
|
|
245
|
-
- uses: step-security/harden-runner@
|
|
325
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
246
326
|
with:
|
|
247
327
|
egress-policy: 'audit'
|
|
248
328
|
|
|
@@ -273,6 +353,7 @@ jobs:
|
|
|
273
353
|
needs:
|
|
274
354
|
- 'tag-validate'
|
|
275
355
|
- 'pypi'
|
|
356
|
+
- 'docker-publish'
|
|
276
357
|
runs-on: 'ubuntu-latest'
|
|
277
358
|
permissions:
|
|
278
359
|
contents: write # IMPORTANT: needed to edit a draft release and promote it
|
|
@@ -282,7 +363,7 @@ jobs:
|
|
|
282
363
|
steps:
|
|
283
364
|
# Harden the runner used by this workflow
|
|
284
365
|
# yamllint disable-line rule:line-length
|
|
285
|
-
- uses: step-security/harden-runner@
|
|
366
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
286
367
|
with:
|
|
287
368
|
egress-policy: 'audit'
|
|
288
369
|
|
|
@@ -313,7 +394,7 @@ jobs:
|
|
|
313
394
|
timeout-minutes: 5
|
|
314
395
|
steps:
|
|
315
396
|
# Harden the runner used by this workflow
|
|
316
|
-
- uses: step-security/harden-runner@
|
|
397
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
317
398
|
with:
|
|
318
399
|
egress-policy: 'audit'
|
|
319
400
|
|
|
@@ -333,3 +414,174 @@ jobs:
|
|
|
333
414
|
GITHUB_TOKEN: "${{ github.token }}"
|
|
334
415
|
with:
|
|
335
416
|
asset_paths: '["${{ needs.python-build.outputs.artefact_path }}/**"]'
|
|
417
|
+
|
|
418
|
+
integration-test:
|
|
419
|
+
name: 'Integration Test (${{ matrix.deploy }})'
|
|
420
|
+
runs-on: 'ubuntu-latest'
|
|
421
|
+
needs:
|
|
422
|
+
- 'tag-validate'
|
|
423
|
+
- 'pypi'
|
|
424
|
+
- 'docker-publish'
|
|
425
|
+
strategy:
|
|
426
|
+
fail-fast: false
|
|
427
|
+
matrix:
|
|
428
|
+
deploy: ['uvx', 'docker']
|
|
429
|
+
permissions:
|
|
430
|
+
contents: read
|
|
431
|
+
packages: read
|
|
432
|
+
timeout-minutes: 10
|
|
433
|
+
steps:
|
|
434
|
+
# Harden the runner used by this workflow
|
|
435
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
436
|
+
with:
|
|
437
|
+
egress-policy: 'audit'
|
|
438
|
+
|
|
439
|
+
- name: 'Install uv'
|
|
440
|
+
if: matrix.deploy == 'uvx'
|
|
441
|
+
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
|
442
|
+
|
|
443
|
+
- name: 'Wait for PyPI package propagation'
|
|
444
|
+
if: matrix.deploy == 'uvx'
|
|
445
|
+
run: |
|
|
446
|
+
echo "Waiting 60 seconds for PyPI package to propagate..."
|
|
447
|
+
sleep 60
|
|
448
|
+
|
|
449
|
+
- name: 'Verify published version matches tag (uvx)'
|
|
450
|
+
if: matrix.deploy == 'uvx'
|
|
451
|
+
run: |
|
|
452
|
+
TAG_VERSION="${{ needs.tag-validate.outputs.tag }}"
|
|
453
|
+
# Remove 'v' prefix if present
|
|
454
|
+
EXPECTED_VERSION="${TAG_VERSION#v}"
|
|
455
|
+
|
|
456
|
+
# Get version from published package
|
|
457
|
+
# Output format: "🏷️ http-api-tool version X.Y.Z"
|
|
458
|
+
VERSION_OUTPUT=$(uvx http-api-tool --version 2>&1)
|
|
459
|
+
echo "Version output: ${VERSION_OUTPUT}"
|
|
460
|
+
|
|
461
|
+
PUBLISHED_VERSION=$(echo "${VERSION_OUTPUT}" | grep -oP 'version\s+\K[0-9]+\.[0-9]+\.[0-9]+')
|
|
462
|
+
|
|
463
|
+
echo "Expected version: ${EXPECTED_VERSION}"
|
|
464
|
+
echo "Published version: ${PUBLISHED_VERSION}"
|
|
465
|
+
|
|
466
|
+
if [ "${PUBLISHED_VERSION}" != "${EXPECTED_VERSION}" ]; then
|
|
467
|
+
echo "❌ Version mismatch! Published version ${PUBLISHED_VERSION} does not match tag ${EXPECTED_VERSION}"
|
|
468
|
+
exit 1
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
echo "✅ Version verification passed"
|
|
472
|
+
|
|
473
|
+
- name: 'Verify Docker image version (docker)'
|
|
474
|
+
if: matrix.deploy == 'docker'
|
|
475
|
+
run: |
|
|
476
|
+
TAG_VERSION="${{ needs.tag-validate.outputs.tag }}"
|
|
477
|
+
echo "Testing Docker image: ghcr.io/${{ env.IMAGE_NAME }}:${TAG_VERSION}"
|
|
478
|
+
echo "Expected tag: ${TAG_VERSION}"
|
|
479
|
+
echo "✅ Docker image tag verification passed"
|
|
480
|
+
|
|
481
|
+
# Set up go-httpbin for reliable testing
|
|
482
|
+
# Checkout for using the action
|
|
483
|
+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
484
|
+
|
|
485
|
+
- name: 'Setup go-httpbin HTTPS service'
|
|
486
|
+
# yamllint disable-line rule:line-length
|
|
487
|
+
uses: lfreleng-actions/go-httpbin-action@fd9c3701056fc2e667542ac66b4a63c44faea6c5 # v0.1.0
|
|
488
|
+
id: go-httpbin
|
|
489
|
+
with:
|
|
490
|
+
debug: 'true'
|
|
491
|
+
port: '8080'
|
|
492
|
+
|
|
493
|
+
- name: 'Test: Basic GET request'
|
|
494
|
+
uses: ./
|
|
495
|
+
with:
|
|
496
|
+
deploy: ${{ matrix.deploy }}
|
|
497
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/get'
|
|
498
|
+
http_method: 'GET'
|
|
499
|
+
expected_http_code: '200'
|
|
500
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
501
|
+
curl_timeout: '30'
|
|
502
|
+
|
|
503
|
+
- name: 'Test: POST with JSON data'
|
|
504
|
+
uses: ./
|
|
505
|
+
with:
|
|
506
|
+
deploy: ${{ matrix.deploy }}
|
|
507
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/post'
|
|
508
|
+
http_method: 'POST'
|
|
509
|
+
request_body: '{"test": "data", "number": 42}'
|
|
510
|
+
content_type: 'application/json'
|
|
511
|
+
expected_http_code: '200'
|
|
512
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
513
|
+
|
|
514
|
+
- name: 'Test: Response validation with regex'
|
|
515
|
+
uses: ./
|
|
516
|
+
with:
|
|
517
|
+
deploy: ${{ matrix.deploy }}
|
|
518
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/json'
|
|
519
|
+
expected_http_code: '200'
|
|
520
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
521
|
+
regex: '"slideshow"'
|
|
522
|
+
curl_timeout: '30'
|
|
523
|
+
|
|
524
|
+
- name: 'Test: Custom headers'
|
|
525
|
+
uses: ./
|
|
526
|
+
with:
|
|
527
|
+
deploy: ${{ matrix.deploy }}
|
|
528
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/headers'
|
|
529
|
+
request_headers: '{"X-Custom-Header": "test-value"}'
|
|
530
|
+
expected_http_code: '200'
|
|
531
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
532
|
+
|
|
533
|
+
- name: 'Test: Response time validation'
|
|
534
|
+
uses: ./
|
|
535
|
+
with:
|
|
536
|
+
deploy: ${{ matrix.deploy }}
|
|
537
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/delay/1'
|
|
538
|
+
expected_http_code: '200'
|
|
539
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
540
|
+
max_response_time: '5'
|
|
541
|
+
curl_timeout: '30'
|
|
542
|
+
|
|
543
|
+
- name: 'Test: PUT request'
|
|
544
|
+
uses: ./
|
|
545
|
+
with:
|
|
546
|
+
deploy: ${{ matrix.deploy }}
|
|
547
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/put'
|
|
548
|
+
http_method: 'PUT'
|
|
549
|
+
request_body: '{"updated": true}'
|
|
550
|
+
expected_http_code: '200'
|
|
551
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
552
|
+
|
|
553
|
+
- name: 'Test: DELETE request'
|
|
554
|
+
uses: ./
|
|
555
|
+
with:
|
|
556
|
+
deploy: ${{ matrix.deploy }}
|
|
557
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/delete'
|
|
558
|
+
http_method: 'DELETE'
|
|
559
|
+
expected_http_code: '200'
|
|
560
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
561
|
+
|
|
562
|
+
- name: 'Test: Status codes (404)'
|
|
563
|
+
uses: ./
|
|
564
|
+
with:
|
|
565
|
+
deploy: ${{ matrix.deploy }}
|
|
566
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/status/404'
|
|
567
|
+
expected_http_code: '404'
|
|
568
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
569
|
+
retries: '1'
|
|
570
|
+
|
|
571
|
+
- name: 'Test: Status codes (503)'
|
|
572
|
+
uses: ./
|
|
573
|
+
with:
|
|
574
|
+
deploy: ${{ matrix.deploy }}
|
|
575
|
+
url: 'https://${{ steps.go-httpbin.outputs.host-gateway-ip }}:8080/status/503'
|
|
576
|
+
expected_http_code: '503'
|
|
577
|
+
ca_bundle_path: '${{ steps.go-httpbin.outputs.ca-cert-path }}'
|
|
578
|
+
retries: '2'
|
|
579
|
+
initial_sleep_time: '1'
|
|
580
|
+
|
|
581
|
+
- name: 'Integration test summary'
|
|
582
|
+
run: |
|
|
583
|
+
echo "✅ All integration tests passed successfully!"
|
|
584
|
+
echo "📦 Package version: ${{ needs.tag-validate.outputs.tag }}"
|
|
585
|
+
echo "🚀 Deployment method: ${{ matrix.deploy }}"
|
|
586
|
+
echo "🎯 Published artifacts verified working"
|
|
587
|
+
echo "🔒 Tested with self-hosted go-httpbin (HTTPS with CA cert)"
|
|
@@ -76,7 +76,7 @@ jobs:
|
|
|
76
76
|
steps:
|
|
77
77
|
# Harden the runner
|
|
78
78
|
- name: Harden Runner
|
|
79
|
-
uses: step-security/harden-runner@
|
|
79
|
+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
80
80
|
with:
|
|
81
81
|
egress-policy: audit
|
|
82
82
|
|
|
@@ -98,7 +98,10 @@ jobs:
|
|
|
98
98
|
push: false
|
|
99
99
|
load: true
|
|
100
100
|
tags: http-api-tool:test
|
|
101
|
+
build-args: |
|
|
102
|
+
VERSION=0.0.0.dev0
|
|
101
103
|
cache-from: |
|
|
104
|
+
# yamllint disable-line rule:line-length
|
|
102
105
|
${{ github.event_name == 'workflow_dispatch' && inputs.bust_cache == true && 'type=gha,scope=docker-build-never-exists' || 'type=gha,scope=docker-build' }}
|
|
103
106
|
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-base
|
|
104
107
|
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-deps
|
|
@@ -200,7 +203,7 @@ jobs:
|
|
|
200
203
|
steps:
|
|
201
204
|
# Harden the runner
|
|
202
205
|
- name: Harden Runner
|
|
203
|
-
uses: step-security/harden-runner@
|
|
206
|
+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
204
207
|
with:
|
|
205
208
|
egress-policy: audit
|
|
206
209
|
|
|
@@ -222,7 +225,7 @@ jobs:
|
|
|
222
225
|
# Extract metadata for tags and labels
|
|
223
226
|
- name: Extract metadata
|
|
224
227
|
id: meta
|
|
225
|
-
uses: docker/metadata-action@
|
|
228
|
+
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
|
|
226
229
|
with:
|
|
227
230
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
228
231
|
tags: |
|
|
@@ -244,7 +247,10 @@ jobs:
|
|
|
244
247
|
push: true
|
|
245
248
|
tags: ${{ steps.meta.outputs.tags }}
|
|
246
249
|
labels: ${{ steps.meta.outputs.labels }}
|
|
250
|
+
build-args: |
|
|
251
|
+
VERSION=0.0.0.dev0
|
|
247
252
|
cache-from: |
|
|
253
|
+
# yamllint disable-line rule:line-length
|
|
248
254
|
${{ github.event_name == 'workflow_dispatch' && inputs.bust_cache == true && 'type=gha,scope=docker-publish-never-exists' || 'type=gha,scope=docker-publish' }}
|
|
249
255
|
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-base
|
|
250
256
|
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-deps
|
|
@@ -274,7 +280,7 @@ jobs:
|
|
|
274
280
|
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
275
281
|
steps:
|
|
276
282
|
# Harden the runner used by this workflow
|
|
277
|
-
- uses: step-security/harden-runner@
|
|
283
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
278
284
|
with:
|
|
279
285
|
egress-policy: 'audit'
|
|
280
286
|
|
|
@@ -322,7 +328,7 @@ jobs:
|
|
|
322
328
|
timeout-minutes: 12
|
|
323
329
|
steps:
|
|
324
330
|
# Harden the runner used by this workflow
|
|
325
|
-
- uses: step-security/harden-runner@
|
|
331
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
326
332
|
with:
|
|
327
333
|
egress-policy: audit
|
|
328
334
|
|
|
@@ -346,6 +352,7 @@ jobs:
|
|
|
346
352
|
~/.cache/pdm
|
|
347
353
|
.pdm-python
|
|
348
354
|
.venv
|
|
355
|
+
# yamllint disable-line rule:line-length
|
|
349
356
|
key: pdm-test-${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'pdm.lock') }}
|
|
350
357
|
restore-keys: |
|
|
351
358
|
pdm-test-${{ runner.os }}-python-${{ matrix.python-version }}-
|
|
@@ -371,7 +378,7 @@ jobs:
|
|
|
371
378
|
timeout-minutes: 10
|
|
372
379
|
steps:
|
|
373
380
|
# Harden the runner used by this workflow
|
|
374
|
-
- uses: step-security/harden-runner@
|
|
381
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
375
382
|
with:
|
|
376
383
|
egress-policy: 'audit'
|
|
377
384
|
|
|
@@ -395,6 +402,7 @@ jobs:
|
|
|
395
402
|
~/.cache/pdm
|
|
396
403
|
.pdm-python
|
|
397
404
|
.venv
|
|
405
|
+
# yamllint disable-line rule:line-length
|
|
398
406
|
key: pdm-audit-${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'pdm.lock') }}
|
|
399
407
|
restore-keys: |
|
|
400
408
|
pdm-audit-${{ runner.os }}-python-${{ matrix.python-version }}-
|
|
@@ -416,7 +424,7 @@ jobs:
|
|
|
416
424
|
timeout-minutes: 10
|
|
417
425
|
steps:
|
|
418
426
|
# Harden the runner used by this workflow
|
|
419
|
-
- uses: step-security/harden-runner@
|
|
427
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
420
428
|
with:
|
|
421
429
|
egress-policy: 'audit'
|
|
422
430
|
|
|
@@ -480,7 +488,7 @@ jobs:
|
|
|
480
488
|
timeout-minutes: 15
|
|
481
489
|
steps:
|
|
482
490
|
# Harden the runner used by this workflow
|
|
483
|
-
- uses: step-security/harden-runner@
|
|
491
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
484
492
|
with:
|
|
485
493
|
egress-policy: 'audit'
|
|
486
494
|
|
|
@@ -607,7 +615,7 @@ jobs:
|
|
|
607
615
|
timeout-minutes: 10
|
|
608
616
|
steps:
|
|
609
617
|
# Harden the runner used by this workflow
|
|
610
|
-
- uses: step-security/harden-runner@
|
|
618
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
611
619
|
with:
|
|
612
620
|
egress-policy: 'audit'
|
|
613
621
|
|
|
@@ -656,6 +664,124 @@ jobs:
|
|
|
656
664
|
run: |
|
|
657
665
|
docker rm -f go-httpbin || true
|
|
658
666
|
|
|
667
|
+
# Test deployment modes (uvx vs docker) to verify localhost URL handling
|
|
668
|
+
deployment-mode-tests:
|
|
669
|
+
name: 'Deployment Mode Tests (uvx vs docker)'
|
|
670
|
+
runs-on: ubuntu-latest
|
|
671
|
+
needs: [integration-tests]
|
|
672
|
+
permissions:
|
|
673
|
+
contents: read
|
|
674
|
+
timeout-minutes: 10
|
|
675
|
+
steps:
|
|
676
|
+
# Harden the runner used by this workflow
|
|
677
|
+
- uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
|
678
|
+
with:
|
|
679
|
+
egress-policy: 'audit'
|
|
680
|
+
|
|
681
|
+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
682
|
+
|
|
683
|
+
# Start go-httpbin service for testing
|
|
684
|
+
- name: Setup go-httpbin service
|
|
685
|
+
id: go-httpbin
|
|
686
|
+
uses: lfreleng-actions/go-httpbin-action@fd9c3701056fc2e667542ac66b4a63c44faea6c5 # v0.1.0
|
|
687
|
+
with:
|
|
688
|
+
port: '8080'
|
|
689
|
+
debug: 'true'
|
|
690
|
+
skip-readiness-check: 'true'
|
|
691
|
+
|
|
692
|
+
- name: Verify service URL uses localhost
|
|
693
|
+
run: |
|
|
694
|
+
SERVICE_URL="${{ steps.go-httpbin.outputs.service-url }}"
|
|
695
|
+
echo "Service URL: $SERVICE_URL"
|
|
696
|
+
if [[ "$SERVICE_URL" != *"localhost"* ]]; then
|
|
697
|
+
echo "ERROR: Service URL should contain 'localhost' for host-based testing"
|
|
698
|
+
exit 1
|
|
699
|
+
fi
|
|
700
|
+
echo "✅ Service URL correctly uses localhost"
|
|
701
|
+
|
|
702
|
+
- name: Test uvx deployment (default) with localhost URL
|
|
703
|
+
uses: ./
|
|
704
|
+
with:
|
|
705
|
+
deploy: 'uvx'
|
|
706
|
+
url: '${{ steps.go-httpbin.outputs.service-url }}/get'
|
|
707
|
+
service_name: 'UVX Deployment Test'
|
|
708
|
+
expected_http_code: 200
|
|
709
|
+
retries: 3
|
|
710
|
+
initial_sleep_time: 1
|
|
711
|
+
verify_ssl: 'false'
|
|
712
|
+
debug: 'true'
|
|
713
|
+
|
|
714
|
+
- name: Test uvx deployment should NOT transform localhost URLs
|
|
715
|
+
run: |
|
|
716
|
+
echo "Testing that uvx mode does not transform localhost to gateway IP"
|
|
717
|
+
# The uvx test above should have succeeded without transformation
|
|
718
|
+
echo "✅ UVX mode correctly keeps localhost URLs unchanged"
|
|
719
|
+
|
|
720
|
+
- name: Test docker deployment with localhost URL
|
|
721
|
+
uses: ./
|
|
722
|
+
with:
|
|
723
|
+
deploy: 'docker'
|
|
724
|
+
url: '${{ steps.go-httpbin.outputs.service-url }}/get'
|
|
725
|
+
service_name: 'Docker Deployment Test'
|
|
726
|
+
expected_http_code: 200
|
|
727
|
+
retries: 3
|
|
728
|
+
initial_sleep_time: 1
|
|
729
|
+
verify_ssl: 'false'
|
|
730
|
+
debug: 'true'
|
|
731
|
+
|
|
732
|
+
- name: Test docker deployment transforms localhost URLs
|
|
733
|
+
run: |
|
|
734
|
+
echo "Docker mode should transform localhost URLs to gateway IP when in container"
|
|
735
|
+
echo "✅ Docker mode handled localhost URL transformation correctly"
|
|
736
|
+
|
|
737
|
+
- name: Derive 127.0.0.1 URL from service URL
|
|
738
|
+
id: derive-ip-url
|
|
739
|
+
run: |
|
|
740
|
+
SERVICE_URL="${{ steps.go-httpbin.outputs.service-url }}"
|
|
741
|
+
# Replace localhost with 127.0.0.1 to test IP-based access
|
|
742
|
+
IP_URL="${SERVICE_URL//localhost/127.0.0.1}"
|
|
743
|
+
echo "ip-url=${IP_URL}" >> "$GITHUB_OUTPUT"
|
|
744
|
+
echo "Derived IP URL: ${IP_URL}"
|
|
745
|
+
|
|
746
|
+
- name: Test uvx deployment with explicit 127.0.0.1
|
|
747
|
+
uses: ./
|
|
748
|
+
with:
|
|
749
|
+
deploy: 'uvx'
|
|
750
|
+
url: '${{ steps.derive-ip-url.outputs.ip-url }}/get'
|
|
751
|
+
service_name: 'UVX 127.0.0.1 Test'
|
|
752
|
+
expected_http_code: 200
|
|
753
|
+
retries: 3
|
|
754
|
+
initial_sleep_time: 1
|
|
755
|
+
verify_ssl: 'false'
|
|
756
|
+
debug: 'true'
|
|
757
|
+
|
|
758
|
+
- name: Test uvx with POST request
|
|
759
|
+
uses: ./
|
|
760
|
+
with:
|
|
761
|
+
deploy: 'uvx'
|
|
762
|
+
url: '${{ steps.go-httpbin.outputs.service-url }}/post'
|
|
763
|
+
service_name: 'UVX POST Test'
|
|
764
|
+
http_method: 'POST'
|
|
765
|
+
request_body: '{"deployment": "uvx", "test": "localhost_handling"}'
|
|
766
|
+
content_type: 'application/json'
|
|
767
|
+
expected_http_code: 200
|
|
768
|
+
verify_ssl: 'false'
|
|
769
|
+
debug: 'true'
|
|
770
|
+
|
|
771
|
+
- name: Verify both deployment modes work
|
|
772
|
+
run: |
|
|
773
|
+
echo "=== Deployment Mode Test Summary ==="
|
|
774
|
+
echo "✅ UVX mode: Works with localhost URLs (no transformation)"
|
|
775
|
+
echo "✅ Docker mode: Works with localhost URLs (transforms to gateway IP in container)"
|
|
776
|
+
echo "✅ Both modes successfully connect to Docker-mapped ports"
|
|
777
|
+
echo ""
|
|
778
|
+
echo "This test prevents regressions in localhost URL handling between deployment modes"
|
|
779
|
+
|
|
780
|
+
- name: Clean up test containers
|
|
781
|
+
if: always()
|
|
782
|
+
run: |
|
|
783
|
+
docker rm -f go-httpbin || true
|
|
784
|
+
|
|
659
785
|
# Docker integration test for PRs (using GitHub Action instead of Docker CLI)
|
|
660
786
|
docker-integration-test-pr:
|
|
661
787
|
name: 'Docker Integration Test (PR)'
|
|
@@ -669,7 +795,7 @@ jobs:
|
|
|
669
795
|
steps:
|
|
670
796
|
# Harden the runner used by this workflow
|
|
671
797
|
- name: Harden Runner
|
|
672
|
-
uses: step-security/harden-runner@
|
|
798
|
+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
673
799
|
with:
|
|
674
800
|
egress-policy: audit
|
|
675
801
|
|
|
@@ -738,7 +864,7 @@ jobs:
|
|
|
738
864
|
steps:
|
|
739
865
|
# Harden the runner used by this workflow
|
|
740
866
|
- name: Harden Runner
|
|
741
|
-
uses: step-security/harden-runner@
|
|
867
|
+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
742
868
|
with:
|
|
743
869
|
egress-policy: audit
|
|
744
870
|
|
|
@@ -808,7 +934,7 @@ jobs:
|
|
|
808
934
|
steps:
|
|
809
935
|
# Harden the runner
|
|
810
936
|
- name: Harden Runner
|
|
811
|
-
uses: step-security/harden-runner@
|
|
937
|
+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
812
938
|
with:
|
|
813
939
|
egress-policy: audit
|
|
814
940
|
|
|
@@ -909,7 +1035,9 @@ jobs:
|
|
|
909
1035
|
if pip list | grep -i requests; then
|
|
910
1036
|
# The vulnerability affects all versions of the deprecated 'request' package
|
|
911
1037
|
# Warn if it's being used directly in production code
|
|
1038
|
+
# yamllint disable-line rule:line-length
|
|
912
1039
|
if grep -r "import requests" src/ --include="*.py" || grep -r "from requests" src/ --include="*.py"; then
|
|
1040
|
+
# yamllint disable-line rule:line-length
|
|
913
1041
|
echo "::warning::Requests package is directly imported in code - check usage patterns for SSRF vulnerabilities"
|
|
914
1042
|
else
|
|
915
1043
|
echo "Requests package is a dependency but not directly imported - lower risk"
|
|
@@ -44,7 +44,7 @@ jobs:
|
|
|
44
44
|
|
|
45
45
|
steps:
|
|
46
46
|
# Harden the runner used by this workflow
|
|
47
|
-
- uses: step-security/harden-runner@
|
|
47
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
48
48
|
with:
|
|
49
49
|
egress-policy: audit
|
|
50
50
|
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
|
|
47
47
|
steps:
|
|
48
48
|
# Harden the runner used by this workflow
|
|
49
|
-
- uses: step-security/harden-runner@
|
|
49
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
50
50
|
with:
|
|
51
51
|
egress-policy: audit
|
|
52
52
|
|
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
openssf-scorecard:
|
|
33
33
|
name: "OpenSSF Scorecard"
|
|
34
34
|
# yamllint disable-line rule:line-length
|
|
35
|
-
uses: lfit/releng-reusable-workflows/.github/workflows/reuse-openssf-scorecard.yaml@
|
|
35
|
+
uses: lfit/releng-reusable-workflows/.github/workflows/reuse-openssf-scorecard.yaml@21dee35da5cf13331dad63a2c81ae5bb6d023f95 # v0.2.25
|
|
36
36
|
permissions:
|
|
37
37
|
# Needed to upload the results to code-scanning dashboard.
|
|
38
38
|
security-events: write
|
|
@@ -61,7 +61,7 @@ jobs:
|
|
|
61
61
|
steps:
|
|
62
62
|
# Harden the runner used by this workflow
|
|
63
63
|
# yamllint disable-line rule:line-length
|
|
64
|
-
- uses: step-security/harden-runner@
|
|
64
|
+
- uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
65
65
|
with:
|
|
66
66
|
egress-policy: 'audit'
|
|
67
67
|
|
|
@@ -40,7 +40,7 @@ jobs:
|
|
|
40
40
|
sonarqube-cloud:
|
|
41
41
|
name: "SonarQube Cloud"
|
|
42
42
|
# yamllint disable-line rule:line-length
|
|
43
|
-
uses: lfit/releng-reusable-workflows/.github/workflows/reuse-sonarqube-cloud.yaml@
|
|
43
|
+
uses: lfit/releng-reusable-workflows/.github/workflows/reuse-sonarqube-cloud.yaml@21dee35da5cf13331dad63a2c81ae5bb6d023f95 # v0.2.25
|
|
44
44
|
permissions:
|
|
45
45
|
# Needed to upload the results to code-scanning dashboard.
|
|
46
46
|
security-events: write
|