diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 3a38397..6e7c0d0 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -17,46 +17,75 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - # v6.0.2 + # yamllint disable-line rule:line-length uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Generate changelog - # v4.5.0 - uses: orhun/git-cliff-action@c93ef52f3d0ddcdcc9bd5447d98d458a11cd4f72 + # yamllint disable-line rule:line-length + uses: orhun/git-cliff-action@c93ef52f3d0ddcdcc9bd5447d98d458a11cd4f72 # v4.5.0 with: config: cliff.toml args: --verbose env: OUTPUT: CHANGELOG.md - - name: Commit changelog + - name: Check for changes + id: diff + run: | + if git diff --quiet CHANGELOG.md 2>/dev/null; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Create pull request + if: steps.diff.outputs.changed == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG_NAME: ${{ github.ref_name }} run: | - if git diff --quiet CHANGELOG.md 2>/dev/null; then - echo "No changes to commit" - exit 0 + BRANCH="chore/changelog-${TAG_NAME}" + + # Reuse existing remote branch if it already exists; otherwise create it. + if git ls-remote --exit-code origin "${BRANCH}" >/dev/null 2>&1; then + echo "Branch ${BRANCH} already exists on origin; checking it out." + git fetch origin "${BRANCH}:${BRANCH}" + git checkout "${BRANCH}" + else + echo "Creating new branch ${BRANCH}." + git checkout -b "${BRANCH}" fi - REPO="${{ github.repository }}" - API_PATH="repos/${REPO}/contents/CHANGELOG.md" - CONTENT=$(base64 -i CHANGELOG.md) - SHA=$(gh api "$API_PATH" \ - --jq '.sha' 2>/dev/null || echo "") - - MSG="docs: update CHANGELOG.md for ${TAG_NAME}" - ARGS=( - -f "message=${MSG}" - -f "content=${CONTENT}" - -f "branch=main" - ) - if [ -n "$SHA" ]; then - ARGS+=(-f "sha=${SHA}") + git add CHANGELOG.md + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Only commit and push if there are staged changes. + if git diff --cached --quiet; then + echo "No changes to commit on branch ${BRANCH}; skipping commit and push." + else + git commit -m "docs: update CHANGELOG.md for ${TAG_NAME}" + git push origin "${BRANCH}" fi - gh api "$API_PATH" \ - --method PUT "${ARGS[@]}" - echo "Changelog updated via GitHub API" + TITLE="docs: update CHANGELOG.md for ${TAG_NAME}" + BODY="Auto-generated changelog update for ${TAG_NAME}." + + # Reuse existing open PR for this branch if present; otherwise create a new one. + PR_NUMBER="$(gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' || true)" + + if [ -z "${PR_NUMBER}" ]; then + echo "No existing pull request for ${BRANCH}; creating a new one." + gh pr create \ + --title "${TITLE}" \ + --body "${BODY}" \ + --base main \ + --head "${BRANCH}" + else + echo "Pull request #${PR_NUMBER} already exists for ${BRANCH}; updating title and body." + gh pr edit "${PR_NUMBER}" \ + --title "${TITLE}" \ + --body "${BODY}" + fi diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 287c98c..7d5806d 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -48,4 +48,5 @@ jobs: GH_TOKEN: ${{ github.token }} TAG_NAME: ${{ github.event.release.tag_name }} run: | - gh release upload "${TAG_NAME}" nsip-sbom-spdx.json + gh release upload "${TAG_NAME}" nsip-sbom-spdx.json \ + --clobber diff --git a/.github/workflows/signed-releases.yml b/.github/workflows/signed-releases.yml index 9a65609..ae0a7e5 100644 --- a/.github/workflows/signed-releases.yml +++ b/.github/workflows/signed-releases.yml @@ -1,9 +1,10 @@ - +--- name: Signed Releases -on: - release: - types: [published] +"on": + workflow_run: + workflows: ["Release"] + types: [completed] permissions: contents: write @@ -13,17 +14,27 @@ jobs: sign-assets: name: Sign Release Assets runs-on: ubuntu-latest - + if: >- + github.event.workflow_run.conclusion == 'success' + && startsWith(github.event.workflow_run.head_branch, 'v') steps: + - name: Get tag name + id: tag + env: + TAG: ${{ github.event.workflow_run.head_branch }} + run: echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + - name: Install Cosign - uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + # yamllint disable-line rule:line-length + uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - name: Download release assets env: GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.tag.outputs.tag }} run: | - gh release download ${{ github.event.release.tag_name }} \ - --repo ${{ github.repository }} \ + gh release download "${TAG}" \ + --repo "${{ github.repository }}" \ --pattern '*' - name: Sign assets with Cosign @@ -48,40 +59,49 @@ jobs: - name: Upload signatures env: GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.tag.outputs.tag }} run: | - gh release upload ${{ github.event.release.tag_name }} \ - --repo ${{ github.repository }} \ + gh release upload "${TAG}" \ + --repo "${{ github.repository }}" \ --clobber \ *.sig SHA256SUMS SHA512SUMS - name: Update release notes env: GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.tag.outputs.tag }} + # yamllint disable rule:line-length run: | - cat >> release_notes.md << 'NOTES' - + EXISTING=$(gh release view "${TAG}" \ + --repo "${{ github.repository }}" \ + --json body -q .body) + + printf '%s\n' "$EXISTING" > release_notes.md + + cat <<'NOTES' >> release_notes.md ## Verification - + All release assets are signed with [Sigstore Cosign](https://github.com/sigstore/cosign). - + ### Verify signatures: - - ```bash + + \`\`\`bash # Install cosign brew install cosign # or download from GitHub - + # Verify asset signature - cosign verify-blob \ - --signature .sig \ - --certificate-identity-regexp=".*" \ - --certificate-oidc-issuer-regexp=".*" \ + cosign verify-blob \\ + --signature .sig \\ + --certificate-identity-regexp=".*" \\ + --certificate-oidc-issuer-regexp=".*" \\ - + # Verify checksums sha256sum --check SHA256SUMS - ``` + \`\`\` NOTES - - gh release edit ${{ github.event.release.tag_name }} \ - --repo ${{ github.repository }} \ + + gh release edit "${TAG}" \ + --repo "${{ github.repository }}" \ --notes-file release_notes.md + # yamllint enable rule:line-length diff --git a/crates/mcp/oauth/token.rs b/crates/mcp/oauth/token.rs index ecfc8eb..c914768 100644 --- a/crates/mcp/oauth/token.rs +++ b/crates/mcp/oauth/token.rs @@ -57,8 +57,8 @@ pub struct TokenResponse { /// Generate an opaque refresh token. fn generate_refresh_token() -> String { - use rand::Rng as _; - let bytes: [u8; 32] = rand::rng().random(); + let mut bytes = [0u8; 32]; + rand::fill(&mut bytes); base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes) }