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
4 changes: 4 additions & 0 deletions .github/workflows/coderepute-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ on:
report-pdf:
description: Path to the generated report.pdf.
value: ${{ jobs.report.outputs.report-pdf }}
card-png:
description: Path to the generated card.png.
value: ${{ jobs.report.outputs.card-png }}

jobs:
report:
Expand All @@ -74,6 +77,7 @@ jobs:
outputs:
attestation-url: ${{ steps.run.outputs.attestation-url }}
report-pdf: ${{ steps.run.outputs.report-pdf }}
card-png: ${{ steps.run.outputs.card-png }}
steps:
- name: Check out the pinned action source
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ comment depth, time to merge, and activity cadence — directly from API
metadata, with no source code access required.

The report runs inside your organization's CI pipeline, attests the output
with a Sigstore signature, and produces a self-contained HTML file and a
machine-readable JSON record that hiring managers and engineering teams can
independently verify have not been edited after collection.
with a Sigstore signature, and produces a self-contained HTML file, a
machine-readable JSON record, and a share card that hiring managers and
engineering teams can independently verify have not been edited after collection.

---

Expand Down Expand Up @@ -303,7 +303,10 @@ gh attestation verify report.html --repo your-org/your-repo
# 2. Verify the PDF report
gh attestation verify report.pdf --repo your-org/your-repo

# 3. Confirm the producing workflow is the canonical CodeRepute action
# 3. Verify the share card
gh attestation verify card.png --repo your-org/your-repo

# 4. Confirm the producing workflow is the canonical CodeRepute action
gh attestation verify report.html --repo your-org/your-repo \
--signer-workflow gkanitz/CodeRepute/.github/workflows/coderepute-report.yml
```
Expand Down Expand Up @@ -332,6 +335,8 @@ what passing verification proves, and what it does not.
|---|---|
| `report.html` | Self-contained HTML with inline SVG charts and embedded report JSON. The HTML file itself is the attested artifact — the embedded JSON is not a separate file. |
| `report.pdf` | CI-generated PDF produced by headless Chromium from `report.html`. Independently attested with its own Sigstore signature. |
| `card.svg` | Static 1200×627 share card with four headline numbers, QR verify link, and Sigstore attestation mark. Self-contained, no external references. |
| `card.png` | CI-generated PNG from `card.svg`, rendered by headless Chromium. Independently attested with its own Sigstore signature. |

---

Expand Down
21 changes: 19 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
name: CodeRepute Report
description: >-
Generate a verified developer collaboration report from GitHub metadata
and attest report.html + report.pdf with Sigstore.
and attest report.html, report.pdf, and card.png with Sigstore.
author: gkanitz

branding:
Expand Down Expand Up @@ -70,6 +70,9 @@ outputs:
report-pdf:
description: Path to the generated report.pdf.
value: ${{ steps.pdf.outputs.report-pdf }}
card-png:
description: Path to the generated card.png.
value: ${{ steps.card-img.outputs.card-png }}
attestation-url:
description: URL of the stored attestation (empty when attest=false).
value: ${{ steps.attest.outputs.attestation-url }}
Expand Down Expand Up @@ -127,14 +130,28 @@ runs:
"file://$(realpath "$CR_OUT/report.html")"
echo "report-pdf=$CR_OUT/report.pdf" >> "$GITHUB_OUTPUT"

- name: Attest report.html and report.pdf
- name: Generate card PNG from card SVG
id: card-img
if: ${{ inputs.attest == 'true' }}
shell: bash
env:
CR_OUT: ${{ inputs.out }}
run: |
google-chrome --headless --disable-gpu --no-sandbox \
--screenshot="$CR_OUT/card.png" \
--window-size=1200,627 \
"file://$(realpath "$CR_OUT/card.svg")"
echo "card-png=$CR_OUT/card.png" >> "$GITHUB_OUTPUT"

- name: Attest report.html, report.pdf, and card.png
id: attest
if: ${{ inputs.attest == 'true' }}
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: |
${{ steps.generate.outputs.report-html }}
${{ steps.pdf.outputs.report-pdf }}
${{ steps.card-img.outputs.card-png }}

- name: Upload report artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
13 changes: 12 additions & 1 deletion cmd/coderepute/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,18 @@ func writeReport(stderr io.Writer, r *report.Report, outDir string) int {
fmt.Fprintf(stderr, "coderepute: %v\n", err)
return 1
}

fmt.Fprintf(stderr, "wrote %s\n", filepath.Join(outDir, "report.html"))

cardSVG, err := render.CardSVG(*r)
if err != nil {
fmt.Fprintf(stderr, "coderepute: card svg: %v\n", err)
return 1
}
if err := os.WriteFile(filepath.Join(outDir, "card.svg"), cardSVG, 0o644); err != nil {
fmt.Fprintf(stderr, "coderepute: %v\n", err)
return 1
}
fmt.Fprintf(stderr, "wrote %s\n", filepath.Join(outDir, "card.svg"))

return 0
}
Loading
Loading