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
71 changes: 71 additions & 0 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Auto Release

# When a version bump lands on main, read the top CHANGELOG version and, if it
# has no matching tag yet, create the tag `vX.Y.Z` and call release.yml to build
# + publish it. No PAT needed — release.yml is invoked via workflow_call because
# the default token cannot let a tag push trigger another workflow.

"on":
push:
branches:
- main
paths:
- CHANGELOG.md # only a version bump can start a release

permissions:
contents: write

concurrency:
group: auto-release
cancel-in-progress: false

jobs:
detect:
name: Detect new version
runs-on: ubuntu-latest
outputs:
release: ${{ steps.ver.outputs.release }}
version: ${{ steps.ver.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # need all tags

- name: Read top CHANGELOG version
id: ver
run: |
# First "## [x.y.z]" heading — skips "## [Unreleased]".
VERSION="$(grep -m1 -oE '^## \[[0-9]+\.[0-9]+\.[0-9]+\]' CHANGELOG.md | tr -d '## []')"
if [ -z "$VERSION" ]; then
echo "No versioned CHANGELOG entry found — nothing to release."
echo "release=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists — skipping."
echo "release=false" >> "$GITHUB_OUTPUT"
Comment on lines +45 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- .github/workflows/auto-release.yml (around lines 35-55) ---\n'
sed -n '35,55p' .github/workflows/auto-release.yml

printf '\n--- search for v$VERSION / rev-parse / show-ref usage ---\n'
rg -n 'rev-parse|show-ref|v\$VERSION|refs/tags/v' .github/workflows -S

Repository: AlfaCode-Team/http

Length of output: 247


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import subprocess, tempfile, os, textwrap, json, sys

# Probe git ref resolution behavior in a scratch repo to test the claim.
repo = tempfile.mkdtemp(prefix="git-ref-probe-")
def run(cmd, cwd=repo):
    return subprocess.run(cmd, cwd=cwd, text=True, capture_output=True)

steps = [
    ["git", "init", "-q"],
    ["git", "config", "user.email", "a@example.com"],
    ["git", "config", "user.name", "a"],
    ["bash", "-lc", "printf x > f && git add f && git commit -q -m init"],
    ["git", "branch", "v1.2.3"],
    ["git", "tag", "v9.9.9"],
]
for cmd in steps:
    r = run(cmd)
    if r.returncode != 0:
        print("FAILED", cmd, r.stderr, file=sys.stderr)
        sys.exit(1)

checks = {
    'branch ref': ['git', 'rev-parse', '--verify', 'v1.2.3^{commit}'],
    'branch name': ['git', 'rev-parse', 'v1.2.3'],
    'exact tag ref existence': ['git', 'show-ref', '--verify', '--quiet', 'refs/tags/v1.2.3'],
    'exact tag ref existence (tag)': ['git', 'show-ref', '--verify', '--quiet', 'refs/tags/v9.9.9'],
    'rev-parse tag': ['git', 'rev-parse', 'v9.9.9'],
}
for label, cmd in checks.items():
    r = run(cmd)
    print(f'## {label}')
    print('cmd:', ' '.join(cmd))
    print('rc:', r.returncode)
    if r.stdout:
        print('stdout:', r.stdout.strip())
    if r.stderr:
        print('stderr:', r.stderr.strip())
    print()
PY

Repository: AlfaCode-Team/http

Length of output: 644


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- .github/workflows/auto-release.yml (around lines 35-55) ---'
sed -n '35,55p' .github/workflows/auto-release.yml

echo
echo '--- search for ref checks in .github/workflows ---'
rg -n 'rev-parse|show-ref|v\$VERSION|refs/tags/v' .github/workflows -S

Repository: AlfaCode-Team/http

Length of output: 1576


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/auto-release.yml')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 35 <= i <= 55:
        print(f"{i:>4}: {line}")
PY

Repository: AlfaCode-Team/http

Length of output: 1130


Check the exact tag ref. git rev-parse "v$VERSION" matches any ref named v$VERSION, including branches, so a real release can be skipped. Use git show-ref --verify --quiet "refs/tags/v$VERSION" instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/auto-release.yml around lines 45 - 47, Update the existing
tag-existence check in the release workflow to verify only the exact tag
reference, using the fully qualified refs/tags/v$VERSION form with git show-ref
--verify --quiet. Preserve the current skip message and release=false output
behavior when that tag exists.

else
echo "New version detected: v$VERSION"
echo "release=true" >> "$GITHUB_OUTPUT"
fi
Comment on lines +45 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== auto-release workflow ==\n'
ast-grep outline .github/workflows/auto-release.yml --view expanded || true

printf '\n== release workflow references ==\n'
rg -n "release\.yml|workflow_call|workflow_dispatch|release=false|release=true|git rev-parse|v\\$VERSION" .github/workflows -n

printf '\n== file snippets ==\n'
nl -ba .github/workflows/auto-release.yml | sed -n '1,160p'
printf '\n---- release workflow ----\n'
nl -ba .github/workflows/release.yml | sed -n '1,220p'

Repository: AlfaCode-Team/http

Length of output: 309


🏁 Script executed:

#!/bin/bash
set -euo pipefail
nl -ba .github/workflows/auto-release.yml | sed -n '1,120p'
echo '----'
nl -ba .github/workflows/release.yml | sed -n '1,220p'

Repository: AlfaCode-Team/http

Length of output: 196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== auto-release ==\n'
sed -n '1,220p' .github/workflows/auto-release.yml

printf '\n== release ==\n'
sed -n '1,260p' .github/workflows/release.yml

printf '\n== references ==\n'
rg -n 'release\.yml|workflow_call|workflow_dispatch|release=false|release=true|git rev-parse|v\$VERSION|VERSION' .github/workflows

Repository: AlfaCode-Team/http

Length of output: 5960


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in .github/workflows/auto-release.yml .github/workflows/release.yml; do
  echo "===== $f ====="
  cat -n "$f" | sed -n '1,220p'
done

Repository: AlfaCode-Team/http

Length of output: 5382


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== auto-release =='
sed -n '1,220p' .github/workflows/auto-release.yml

echo
echo '== release =='
sed -n '1,260p' .github/workflows/release.yml

echo
echo '== matches =='
rg -n 'release\.yml|workflow_call|workflow_dispatch|release=false|release=true|git rev-parse|v\$VERSION|VERSION' .github/workflows/auto-release.yml .github/workflows/release.yml

Repository: AlfaCode-Team/http

Length of output: 5957


Always call release.yml even when v$VERSION already exists. release.yml is idempotent, so skipping it here makes a failed first run unrecoverable: reruns will hit release=false and never recreate the missing GitHub Release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/auto-release.yml around lines 45 - 51, Update the
version-check flow around the release output to always set release=true and
invoke release.yml, including when the v$VERSION tag already exists. Remove the
existing release=false skip path while preserving the informational tag-exists
logging.


- name: Create and push tag
if: steps.ver.outputs.release == 'true'
env:
VERSION: ${{ steps.ver.outputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "v$VERSION" -m "Release v$VERSION"
git push origin "v$VERSION"

release:
name: Build & publish
needs: detect
if: needs.detect.outputs.release == 'true'
uses: ./.github/workflows/release.yml
permissions:
contents: write
with:
version: ${{ needs.detect.outputs.version }}
31 changes: 28 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
name: Release

# Publishes a GitHub Release. Two entry points:
# • a pushed tag `v*` — manual escape hatch
# • workflow_call(version) — invoked by auto-release.yml on merge to main
# (the default token cannot let a tag push trigger this workflow, so the
# auto-release path calls it directly).

on:
push:
tags:
- 'v*'
workflow_call:
inputs:
version:
description: 'Release version without the leading v (e.g. 1.2.0)'
required: true
type: string

permissions:
contents: write
Expand Down Expand Up @@ -34,11 +46,24 @@ jobs:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Create release
- name: Resolve tag
id: tag
run: |
if [ -n "${{ inputs.version }}" ]; then
echo "tag=v${{ inputs.version }}" >> "$GITHUB_OUTPUT"
else
echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
fi
Comment on lines +49 to +56

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the workflow and any callers first.
git ls-files '.github/workflows/*' '.*' | sed -n '1,200p'

Repository: AlfaCode-Team/http

Length of output: 462


🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files .github/workflows | sed -n '1,200p'

Repository: AlfaCode-Team/http

Length of output: 246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant workflow section with line numbers.
cat -n .github/workflows/release.yml | sed -n '1,140p'

Repository: AlfaCode-Team/http

Length of output: 2526


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find workflow callers and references to the release workflow.
rg -n "release\.yml|workflow_call|inputs\.version|Resolve tag" .github/workflows -S

Repository: AlfaCode-Team/http

Length of output: 871


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== workflow files ==="
git ls-files .github/workflows

echo "=== release.yml lines 1-180 ==="
cat -n .github/workflows/release.yml | sed -n '1,180p'

Repository: AlfaCode-Team/http

Length of output: 2671


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== search for reusable workflow declaration and callers ==="
rg -n "workflow_call|uses: \.\/\.github\/workflows\/release\.yml|inputs\.version|version:" .github/workflows -S

Repository: AlfaCode-Team/http

Length of output: 1199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n .github/workflows/release.yml | sed -n '1,180p'

Repository: AlfaCode-Team/http

Length of output: 2526


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/release.yml')
print(p.read_text())
PY

Repository: AlfaCode-Team/http

Length of output: 2044


Don't interpolate inputs.version directly into this shell step. In .github/workflows/release.yml:49-56, a caller can inject shell syntax or extra $GITHUB_OUTPUT lines here. Pass it through env, validate it, and write it with printf.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 52-52: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 53-53: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 49 - 56, Update the “Resolve tag”
step to pass inputs.version through the step environment instead of
interpolating it in the shell. Validate the environment value before use, then
write the tag output with printf so caller-supplied shell syntax or extra
GITHUB_OUTPUT lines cannot be interpreted.

Source: Linters/SAST tools

- name: Create release (idempotent)
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.tag.outputs.tag }}
run: |
gh release create "${GITHUB_REF_NAME}" \
--title "${GITHUB_REF_NAME}" \
if gh release view "$TAG" >/dev/null 2>&1; then
echo "Release $TAG already exists — nothing to do."
exit 0
fi
gh release create "$TAG" \
--title "$TAG" \
--generate-notes \
--verify-tag
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.0.0] - 2026-07-22

### Added

- Initial extraction of the PhpServicePlatform kernel HTTP layer into a standalone,
Expand Down