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.
Files changed (46) hide show
  1. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/build-test-release.yaml +260 -8
  2. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/build-test.yaml +140 -12
  3. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/dependencies.yaml +1 -1
  4. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/documentation.yaml +1 -1
  5. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/openssf-scorecard.yaml +1 -1
  6. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/release-drafter.yaml +1 -1
  7. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/security-scans.yaml +1 -1
  8. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/semantic-pull-request.yaml +1 -1
  9. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/verify-gha-versions.yaml +1 -1
  10. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.gitignore +1 -0
  11. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.pre-commit-config.yaml +15 -9
  12. http_api_tool-1.0.2/CHANGELOG-v0.2.0.md +296 -0
  13. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/Dockerfile +11 -2
  14. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/Makefile +8 -0
  15. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/PKG-INFO +131 -5
  16. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/README.md +129 -4
  17. http_api_tool-1.0.2/action.yaml +302 -0
  18. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/pyproject.toml +29 -2
  19. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/scripts/generate_requirements.py +0 -0
  20. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/__init__.py +1 -1
  21. http_api_tool-1.0.2/src/http_api_tool/_version.py +34 -0
  22. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/cli.py +27 -1
  23. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/uv.lock +1 -95
  24. http_api_tool-1.0.0/action.yaml +0 -157
  25. http_api_tool-1.0.0/scripts/README.md +0 -168
  26. http_api_tool-1.0.0/scripts/requirements_header.txt +0 -2
  27. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.actrc +0 -0
  28. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.codespell +0 -0
  29. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.dockerignore +0 -0
  30. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.editorconfig +0 -0
  31. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/cache-config.yaml +0 -0
  32. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/dependabot.yml +0 -0
  33. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/release-drafter.yml +0 -0
  34. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.github/workflows/codeql.yml +0 -0
  35. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.gitlint +0 -0
  36. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.readthedocs.yml +0 -0
  37. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/.yamllint +0 -0
  38. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/LICENSE +0 -0
  39. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/LICENSES/Apache-2.0.txt +0 -0
  40. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/REUSE.toml +0 -0
  41. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/UV-QUICK-REFERENCE.md +0 -0
  42. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/scripts/check-pip-security.py +0 -0
  43. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/sonar-project.properties +0 -0
  44. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/__main__.py +0 -0
  45. {http_api_tool-1.0.0 → http_api_tool-1.0.2}/src/http_api_tool/verifier.py +0 -0
  46. {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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@b138097fe80abdc0f3d220787cbd82dbe231179c # v0.2.24
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@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
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@b138097fe80abdc0f3d220787cbd82dbe231179c # v0.2.24
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