Skip to content

Add 'Request a Repo' button and issue template#3

Merged
jonathanpopham merged 3 commits intomainfrom
feat/request-a-repo
Mar 2, 2026
Merged

Add 'Request a Repo' button and issue template#3
jonathanpopham merged 3 commits intomainfrom
feat/request-a-repo

Conversation

@jonathanpopham
Copy link
Contributor

@jonathanpopham jonathanpopham commented Mar 2, 2026

Summary

End-to-end self-service repo onboarding — from paste to published.

User-facing: Inline submit form on the homepage

  • Paste a GitHub URL (or owner/repo) into the form below the search box
  • Instant preview: "Docs will be at repos.supermodeltools.com/{name}/"
  • One click opens a pre-filled GitHub issue, automation handles the rest
  • When search returns no results, "Request this repo" scrolls to the form
  • "+ Request a Repo" button in the nav header as an additional entry point

Automation: Issue-triggered pipeline (auto-add-repo.yml)

When an issue with repo-request label is created:

  1. Parses and validates the repo (public, not archived, not empty, not duplicate)
  2. Auto-detects description + language → pill/color from GitHub API
  3. Forks into supermodeltools org
  4. Sets SUPERMODEL_API_KEY secret, pushes arch-docs.yml workflow, enables Pages
  5. Triggers the arch-docs build
  6. Adds repo to repos.yaml → homepage auto-rebuilds
  7. Comments on issue with the docs link and closes it

Automation: Org-wide sync (sync-repos.yml)

Runs every 6 hours (+ manual trigger). Catches repos set up internally that were never added to the homepage:

  • Scans all repos in the org for arch-docs.yml workflow
  • Compares against repos.yaml
  • Auto-adds missing repos (forks → Community, org-native → Supermodel Open Source)
  • Auto-detects metadata from GitHub API

This would have caught volt — and the 10 other repos currently missing from the homepage.

Issue template

Simplified to a single field: just the GitHub URL. Everything else is auto-detected.

Required secrets

Secret Purpose
BOT_TOKEN PAT with repo + admin:org scope — fork repos, set secrets, push workflows, push commits that trigger other workflows
SUPERMODEL_API_KEY Passed to forked repos for the arch-docs GitHub Action

Files changed

File What
generate-index.go Inline submit form + preview + no-results CTA + mobile styles
.github/ISSUE_TEMPLATE/request-repo.yml Single-field issue form (just URL)
.github/workflows/auto-add-repo.yml Issue-triggered full pipeline
.github/workflows/sync-repos.yml Cron sync for org-wide discovery

Closes supermodeltools/arch-docs#13

Test plan

  • go run generate-index.go builds successfully
  • Submit form renders below search, preview shows on valid URL input
  • Enter key and button click both work
  • "No results" link scrolls to and pre-fills the submit form
  • Mobile layout stacks input + button vertically
  • Set BOT_TOKEN + SUPERMODEL_API_KEY secrets
  • Submit a test request issue → verify full pipeline
  • Manually trigger sync workflow → verify missing repos get added
  • Verify homepage rebuilds after repos.yaml changes

Summary by CodeRabbit

  • New Features

    • Added a "Request a Repo" button in site navigation and a submit box under search with live preview for pasted repo URLs.
    • No-results area now offers a "Request docs for this repo" shortcut that pre-fills and focuses the submit input.
    • Added a guided issue template to capture required repository URL and details.
  • Chores / Automation

    • Added automated workflows to validate, add, and sync requested public repositories, and to post status comments on request issues.

Add a GitHub issue template with a structured form for anyone to
request a public repository be added to the architecture docs.
Add a styled "Request a Repo" button in the site header nav that
links directly to the issue template.

Closes supermodeltools/arch-docs#13
@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

Walkthrough

Adds a "Request a Repo" flow: issue template for repo requests, homepage UI (button, submit box, live repo-preview, no-results trigger) to open a pre-filled request, and two GitHub Actions workflows — one to auto-validate/add requested repos and one to periodically sync org repos into repos.yaml.

Changes

Cohort / File(s) Summary
Issue Template
​.github/ISSUE_TEMPLATE/request-repo.yml
New structured issue template that requires a validated repo_url, sets labels, and provides a prefilled body for repo requests.
Frontend — Homepage & Search UI
generate-index.go
Adds "Request a Repo" header button, a submit box under search with repo URL parsing, live preview and validation, a no-results "Request docs for this repo" trigger, and related CSS/layout changes. Attention: client-side parsing, prefilled issue URL encoding, and responsive styles.
Auto-add Workflow
​.github/workflows/auto-add-repo.yml
New workflow that parses repo URL from issue, validates via GitHub API (public, not archived/empty), maps language pill, forks upstream into org if needed, sets secrets, enables Pages, injects arch-docs workflow, appends entry to repos.yaml (yq), commits/pushes, comments and closes the issue. Attention: token/secret usage, forking logic, yq YAML edits, and race-condition handling.
Sync Workflow
​.github/workflows/sync-repos.yml
Scheduled/manual workflow that scans org repos for arch-docs, filters out existing entries, enriches metadata, categorizes (Community vs OSS), appends new entries to repos.yaml, and commits/pushes when additions exist. Attention: repo discovery/filtering logic and yq updates.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as User
    participant Site as Repos Site (UI)
    participant GH as GitHub Issues
    participant Workflow as GitHub Actions
    participant API as GitHub API
    participant RepoYAML as repos.yaml

    User->>Site: Click "Request a Repo" / paste repo URL
    Site->>GH: Open new issue (template=request-repo.yml) with prefilled repo_url
    GH->>Workflow: Issue opened / labeled (repo-request)
    Workflow->>API: Parse/normalize URL -> validate (exists, public, not archived/empty)
    API-->>Workflow: Repo metadata (desc, language, stars, default branch)
    Workflow->>API: Fork upstream into org (if needed) / set secrets / enable Pages
    Workflow->>RepoYAML: Pull latest, append new entry (yq)
    RepoYAML-->>Workflow: Commit & push changes
    Workflow->>GH: Comment result and close issue
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A button, a URL, a tiny plea,
Forms and workflows hum quietly,
A fork, a YAML line set true,
Pages switch on, a listing new,
One click, one ticket — docs come through. 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes two additional workflows (auto-add-repo.yml and sync-repos.yml) that go beyond the minimal issue #13 scope, adding full automation for repo validation, forking, and homepage updates. Consider scoping these changes to a separate PR or clearly document them as enhancements. If intentional, update the PR description to outline these automation additions and their necessity.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: adding a 'Request a Repo' button and issue template, which are the primary user-facing features introduced in this PR.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #13: issue template with repo URL field, 'Request a Repo' button in header with link to template, and comprehensive automation via GitHub Actions workflows.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/request-a-repo

Comment @coderabbitai help to get the list of available commands and usage tips.

- Simplify issue template to just a URL field (low friction)
- Add auto-add-repo.yml workflow that triggers on issue creation:
  - Validates repo (public, not archived, not empty, not duplicate)
  - Auto-detects description, language, pill from GitHub API
  - Forks repo into org, sets up arch-docs workflow, enables Pages
  - Appends to repos.yaml and commits (triggers homepage rebuild)
  - Comments on issue with result and closes it

Required secrets: BOT_TOKEN (PAT with repo + admin:org scope),
SUPERMODEL_API_KEY (for arch-docs on forked repos)
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
.github/workflows/auto-add-repo.yml (1)

261-268: categories[1] is brittle if ordering changes.

Line 262 assumes Community is always index 1. If categories are reordered, this writes into the wrong bucket.

Append by category name instead of index
-          yq -i '.categories[1].repos += [{
+          yq -i '(.categories[] | select(.name == "Community") | .repos) += [{
             "name": strenv(REPO_NAME),
             "upstream": strenv(UPSTREAM),
             "description": strenv(DESCRIPTION),
             "pill": strenv(PILL),
             "pill_class": strenv(PILL_CLASS)
           }]' repos.yaml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/auto-add-repo.yml around lines 261 - 268, The current yq
invocation targets '.categories[1].repos' which is brittle; change the yq
expression to locate the category object by its "name" field (e.g., the category
named "Community") and append the new repo into that object's "repos" array in
repos.yaml instead of using index 1; update the yq command that currently
references '.categories[1].repos' so it selects the category where .name ==
"Community" (or uses an equivalent selector) and then adds the repo entry with
the same fields (REPO_NAME, UPSTREAM, DESCRIPTION, PILL, PILL_CLASS).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/ISSUE_TEMPLATE/request-repo.yml:
- Around line 11-18: The template currently only defines the input field with id
repo_url; add structured fields to capture
category/tag/description/optional_reason by extending the YAML to include new
inputs (e.g., type: select or input with ids like category, tags, description,
reason), provide labels and placeholders, and set appropriate validations
(required for category and description, optional for reason) so triage context
is collected; update the existing block that contains id: repo_url to remain and
append new field definitions such as id: category, id: tags, id: description,
id: optional_reason with sensible attributes and validations.

In @.github/workflows/auto-add-repo.yml:
- Around line 84-89: The current duplicate detection uses a regex grep on
repos.yaml ("grep \"^      - name: ${REPO_NAME}$\"") which is fragile when
REPO_NAME contains regex metacharacters and only checks the name field; replace
this with a YAML-aware exact-match check using yq: query the YAML structure
(e.g., search the list entries for .name == env(REPO_NAME) or compare the
combined owner/name if available) to perform a literal equality test and return
a non-zero/zero result for existence; update the step to use REPO_NAME (and
REPO_OWNER if present) with yq so matching is exact and robust against special
characters instead of the current grep line.
- Around line 13-18: The workflow currently triggers privileged actions when
only the user-set label 'repo-request' is present; update the workflow condition
to require a maintainer-controlled approval label as well (e.g., require both
contains(github.event.issue.labels.*.name, 'repo-request') and
contains(github.event.issue.labels.*.name, 'repo-request-approved')) so only
maintainers can enable the privileged path, and apply the same change to the
"Fork and setup arch-docs" step; ensure any checks that use secrets.BOT_TOKEN or
secrets.SUPERMODEL_API_KEY are behind this strengthened if-condition (or an
explicit maintainer approval step) to prevent unapproved public-triggered use of
those secrets.
- Around line 175-216: The child workflow's environment.url is referencing a
step output that doesn't exist yet (environment.url: ${{
steps.deploy.outputs.page_url }} while the deploy step is the last step id:
deploy using actions/deploy-pages@v4); fix by ensuring the URL value is produced
before it's referenced—either move the deploy step earlier so steps.deploy runs
before the environment block or add a step immediately after
actions/deploy-pages@v4 that captures its output (read the page_url from the
deploy action output and write it to GITHUB_OUTPUT or set a step output with an
id) and then reference that new step id in environment.url instead of
steps.deploy.outputs.page_url; update WORKFLOW_CONTENT accordingly so the child
workflow contains the corrected step ordering or the intermediate output-writing
step.

---

Nitpick comments:
In @.github/workflows/auto-add-repo.yml:
- Around line 261-268: The current yq invocation targets '.categories[1].repos'
which is brittle; change the yq expression to locate the category object by its
"name" field (e.g., the category named "Community") and append the new repo into
that object's "repos" array in repos.yaml instead of using index 1; update the
yq command that currently references '.categories[1].repos' so it selects the
category where .name == "Community" (or uses an equivalent selector) and then
adds the repo entry with the same fields (REPO_NAME, UPSTREAM, DESCRIPTION,
PILL, PILL_CLASS).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a682c64 and fa6acbf.

📒 Files selected for processing (2)
  • .github/ISSUE_TEMPLATE/request-repo.yml
  • .github/workflows/auto-add-repo.yml

Comment on lines +11 to +18
- type: input
id: repo_url
attributes:
label: Repository URL
description: "GitHub URL (e.g. https://github.com/facebook/react)"
placeholder: "https://github.com/owner/repo"
validations:
required: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Template is missing structured fields from the stated feature goals.

Right now only repo_url is collected. The linked objective calls out structured fields like category/tag/description/optional reason, so triage context is still missing.

Suggested expansion
   - type: input
     id: repo_url
@@
     validations:
       required: true
+
+  - type: dropdown
+    id: category
+    attributes:
+      label: Category
+      options:
+        - Community
+        - Official
+        - Experimental
+    validations:
+      required: true
+
+  - type: input
+    id: tag
+    attributes:
+      label: Tag
+      description: "Short tag used for grouping/search (optional)"
+    validations:
+      required: false
+
+  - type: textarea
+    id: description
+    attributes:
+      label: Description
+      description: "Brief summary of why this repo should be listed"
+    validations:
+      required: true
+
+  - type: textarea
+    id: reason
+    attributes:
+      label: Additional context
+      description: "Optional notes for maintainers"
+    validations:
+      required: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- type: input
id: repo_url
attributes:
label: Repository URL
description: "GitHub URL (e.g. https://github.com/facebook/react)"
placeholder: "https://github.com/owner/repo"
validations:
required: true
- type: input
id: repo_url
attributes:
label: Repository URL
description: "GitHub URL (e.g. https://github.com/facebook/react)"
placeholder: "https://github.com/owner/repo"
validations:
required: true
- type: dropdown
id: category
attributes:
label: Category
options:
- Community
- Official
- Experimental
validations:
required: true
- type: input
id: tag
attributes:
label: Tag
description: "Short tag used for grouping/search (optional)"
validations:
required: false
- type: textarea
id: description
attributes:
label: Description
description: "Brief summary of why this repo should be listed"
validations:
required: true
- type: textarea
id: reason
attributes:
label: Additional context
description: "Optional notes for maintainers"
validations:
required: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/ISSUE_TEMPLATE/request-repo.yml around lines 11 - 18, The template
currently only defines the input field with id repo_url; add structured fields
to capture category/tag/description/optional_reason by extending the YAML to
include new inputs (e.g., type: select or input with ids like category, tags,
description, reason), provide labels and placeholders, and set appropriate
validations (required for category and description, optional for reason) so
triage context is collected; update the existing block that contains id:
repo_url to remain and append new field definitions such as id: category, id:
tags, id: description, id: optional_reason with sensible attributes and
validations.

Comment on lines +13 to +18
if: contains(github.event.issue.labels.*.name, 'repo-request')
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
env:
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find and examine the workflow file
find . -name "auto-add-repo.yml" -type f

Repository: supermodeltools/supermodeltools.github.io

Length of output: 122


🏁 Script executed:

# Also check the repository structure for context
git ls-files | grep -E "\.(yml|yaml)$" | head -20

Repository: supermodeltools/supermodeltools.github.io

Length of output: 205


🌐 Web query:

GitHub Actions issue event security: can external users trigger workflows with secrets

💡 Result:

Yes—external users can trigger GitHub Actions workflows that have access to your repository secrets if you run workflows on issues or issue_comment.

What happens with issues / issue_comment

  • These events run workflows using the workflow file on the default branch (not from the attacker’s fork/branch). [1]
  • Because the run is in the context of the base repository, it can generally access repository/environment secrets and a non-readonly GITHUB_TOKEN, unless you restrict permissions. This is why GitHub Security Lab warns that event triggers like issues / issue_comment can have higher impact than pull_request if you have injection or unsafe command execution. [2]

Why this is dangerous

If your workflow:

  • takes attacker-controlled text (issue title/body/comment) and uses it in run: scripts, or
  • treats comments as “commands” (e.g., /deploy) and then runs privileged steps,
    an attacker can potentially get code execution in a context where secrets are available, and then exfiltrate them (e.g., via printenv, network calls, artifacts). [2]

A common pitfall is triggering on issue_comment and then checking out/building code from a PR branch—this pattern is widely considered risky for “pwn request”-style attacks. [2]

Contrast with pull_request from forks

  • GitHub’s key safety guarantee is: pull_request workflows from forks do not receive repository secrets and get a read-only token, limiting blast radius. [3]

Practical mitigations

  • Set least privilege: permissions: read-all (or narrower) and only add writes per job/step.
  • Never interpolate issue/comment fields into shell commands; treat them as untrusted input (escape/parse safely). [2]
  • If you use comment-driven automation, gate it (e.g., require author_association to be MEMBER/OWNER, or require a maintainer “approval” action before any secret-using job runs).
  • Avoid privileged triggers like pull_request_target unless you fully understand the risk and never execute untrusted PR code with secrets. [4]

Sources: GitHub docs on workflow trigger behavior for issue_comment/default-branch workflows [1]; GitHub Security Lab guidance on untrusted input and impact differences across events [2]; GitHub blog on fork PR runs having no secrets/read-only token [3]; GitHub guidance warning about privileged triggers like pull_request_target [4].

References: [1] (docs.github.com) [2] (securitylab.github.com) [3] (github.blog) [4] (wellarchitected.github.com)

Citations:


🌐 Web query:

GitHub Actions repository secrets accessible from issue triggered workflows

💡 Result:

Yes. Workflows triggered by issue-based events like issues and issue_comment run in the context of the base repository, so they can access repository/environment/org secrets via the secrets context and also receive a GITHUB_TOKEN (subject to whatever permissions: you configure and the repo’s defaults). This differs from pull_request runs from forks, where repository secrets are not provided. [1], [2], [3]

Security implication: because anyone who can open/comment on an issue can often trigger these workflows, treating issue titles/bodies/comments as untrusted input is critical—unsafe use in run: steps can lead to command injection and secret exfiltration. GitHub explicitly highlights that permissions/secret exposure varies by trigger and calls out issues / issue_comment as higher-impact than forked pull_request in this respect. [4]

Key references

  • Secrets are not passed to workflows triggered by pull requests from forks (and some other restricted initiators, e.g., Dependabot). [1]
  • GITHUB_TOKEN usage/availability in workflows. [3]
  • Why untrusted input (including issue content) can lead to secret theft in Actions. [4]

Sources: GitHub Docs on secret restrictions [1], GitHub Blog on fork PR privilege reduction [2], GitHub Docs on GITHUB_TOKEN [3], GitHub Security Lab guidance on untrusted input in Actions [4].


🌐 Web query:

GitHub recommended approval pattern for issue triggered workflows

💡 Result:

GitHub’s recommended pattern is: don’t run privileged work (secrets, deployments, write tokens) directly from issues / issue_comment triggers. Instead, use a maintainer-controlled gate and (for sensitive steps) environment approvals.

1) Don’t trust issues / issue_comment as the approval gate

issue_comment runs from the default branch context and can be triggered by comments (including on PRs), which is a known way to bypass PR-approval-based protections if you treat “commenting” as authorization. The event also uses the default branch SHA/ref (not the PR’s), which is another reason it’s a risky trigger for privileged work. [3], [4]

2) Use a maintainer-controlled “gate” (recommended: label gate)

Use a workflow that only proceeds when a trusted actor applies a specific label (or otherwise performs an action that only collaborators/maintainers can do), e.g.:

  • trigger on pull_request labeled (or issues labeled) and require label.name == 'ok-to-run'
  • optionally also check the labeler is trusted (org member / repo collaborator)

GitHub Security Lab explicitly recommends shifting from comment-triggers to label gates for this kind of approval control. [4]

3) Put the privileged job behind a protected Environment (manual approval)

For anything that uses real secrets or deploys, target a GitHub Actions environment with “Required reviewers”. The job will pause “awaiting review” until an authorized reviewer approves it. [1]
If you want to prevent the same person who triggered the run from approving it, GitHub added an option to prevent self-reviews for environment approvals. [2]

Sources:
[1] GitHub Docs – Reviewing deployments (environment required reviewers / approval flow) https://docs.github.com/actions/managing-workflow-runs/reviewing-deployments
[2] GitHub Changelog – Prevent self-reviews for environment approvals https://github.blog/changelog/2023-10-16-actions-prevent-self-reviews-for-secure-deployments-across-actions-environments/
[3] GitHub Docs – Events that trigger workflows (issue_comment uses default branch SHA/ref; default-branch workflow file requirement) https://docs.github.com/en/enterprise-server%403.15/actions/reference/events-that-trigger-workflows
[4] GitHub Security Lab – issue_comment can bypass approval mechanisms; recommends label gates https://securitylab.github.com/resources/github-actions-new-patterns-and-mitigations/


🏁 Script executed:

cat -n .github/workflows/auto-add-repo.yml

Repository: supermodeltools/supermodeltools.github.io

Length of output: 15590


Lock privileged workflow behind a maintainer approval gate.

Any public user can open a labeled issue and trigger fork/secret creation in your org. The workflow currently checks only for the repo-request label (which users can apply themselves), then uses secrets.BOT_TOKEN and secrets.SUPERMODEL_API_KEY to fork repos, inject workflows, and configure secrets on org-owned forks.

This is a critical security risk. GitHub recommends gating privileged issues-triggered workflows with a maintainer-controlled label (e.g., requiring both repo-request and repo-request-approved, where only maintainers can apply the approval label). Alternatively, use an explicit maintainer approval step.

Suggested fix: require maintainer approval label
 jobs:
   process-request:
-    if: contains(github.event.issue.labels.*.name, 'repo-request')
+    if: |
+      contains(github.event.issue.labels.*.name, 'repo-request') &&
+      contains(github.event.issue.labels.*.name, 'repo-request-approved')

Also applies to the "Fork and setup arch-docs" step (lines 145–169) which deploys secrets and creates org infrastructure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/auto-add-repo.yml around lines 13 - 18, The workflow
currently triggers privileged actions when only the user-set label
'repo-request' is present; update the workflow condition to require a
maintainer-controlled approval label as well (e.g., require both
contains(github.event.issue.labels.*.name, 'repo-request') and
contains(github.event.issue.labels.*.name, 'repo-request-approved')) so only
maintainers can enable the privileged path, and apply the same change to the
"Fork and setup arch-docs" step; ensure any checks that use secrets.BOT_TOKEN or
secrets.SUPERMODEL_API_KEY are behind this strengthened if-condition (or an
explicit maintainer approval step) to prevent unapproved public-triggered use of
those secrets.

Comment on lines +84 to +89
# 5. Must not already be listed
if grep -q "^ - name: ${REPO_NAME}$" repos.yaml; then
echo "error=true" >> "$GITHUB_OUTPUT"
echo "error_msg=Repository \`$REPO_NAME\` is already listed on the homepage." >> "$GITHUB_OUTPUT"
exit 0
fi
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Duplicate detection is regex-fragile and only checks name.

grep "^ - name: ${REPO_NAME}$" can false-match (regex chars in names) and misses upstream-duplicate checks. Example: foo.bar behaves like a regex, not a literal.

Use exact YAML matching via yq
-          if grep -q "^      - name: ${REPO_NAME}$" repos.yaml; then
+          if yq -e '
+            .categories[].repos[] |
+            select(.name == strenv(REPO_NAME) or .upstream == strenv(UPSTREAM))
+          ' repos.yaml >/dev/null; then
             echo "error=true" >> "$GITHUB_OUTPUT"
-            echo "error_msg=Repository \`$REPO_NAME\` is already listed on the homepage." >> "$GITHUB_OUTPUT"
+            echo "error_msg=Repository \`$UPSTREAM\` is already listed on the homepage." >> "$GITHUB_OUTPUT"
             exit 0
           fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# 5. Must not already be listed
if grep -q "^ - name: ${REPO_NAME}$" repos.yaml; then
echo "error=true" >> "$GITHUB_OUTPUT"
echo "error_msg=Repository \`$REPO_NAME\` is already listed on the homepage." >> "$GITHUB_OUTPUT"
exit 0
fi
# 5. Must not already be listed
if yq -e '
.categories[].repos[] |
select(.name == strenv(REPO_NAME) or .upstream == strenv(UPSTREAM))
' repos.yaml >/dev/null; then
echo "error=true" >> "$GITHUB_OUTPUT"
echo "error_msg=Repository \`$UPSTREAM\` is already listed on the homepage." >> "$GITHUB_OUTPUT"
exit 0
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/auto-add-repo.yml around lines 84 - 89, The current
duplicate detection uses a regex grep on repos.yaml ("grep \"^      - name:
${REPO_NAME}$\"") which is fragile when REPO_NAME contains regex metacharacters
and only checks the name field; replace this with a YAML-aware exact-match check
using yq: query the YAML structure (e.g., search the list entries for .name ==
env(REPO_NAME) or compare the combined owner/name if available) to perform a
literal equality test and return a non-zero/zero result for existence; update
the step to use REPO_NAME (and REPO_OWNER if present) with yq so matching is
exact and robust against special characters instead of the current grep line.

Comment on lines +175 to +216
WORKFLOW_CONTENT='name: Architecture Docs

on:
push:
branches: [main, master]
workflow_dispatch:

permissions:
contents: write
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: true

jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/checkout@v4

- uses: supermodeltools/arch-docs@main
id: docs
with:
supermodel-api-key: ${{ secrets.SUPERMODEL_API_KEY }}

- uses: actions/configure-pages@v5

- uses: actions/upload-pages-artifact@v3
with:
path: ./arch-docs-output

- uses: actions/deploy-pages@v4
id: deploy'

# Dedent the workflow content (remove leading spaces from heredoc)
WORKFLOW_CONTENT=$(echo "$WORKFLOW_CONTENT" | sed 's/^ //')
ENCODED=$(echo -n "$WORKFLOW_CONTENT" | base64 -w0)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd .github/workflows && ls -la auto-add-repo.yml

Repository: supermodeltools/supermodeltools.github.io

Length of output: 152


🏁 Script executed:

cat -n .github/workflows/auto-add-repo.yml | head -220 | tail -60

Repository: supermodeltools/supermodeltools.github.io

Length of output: 2486


🏁 Script executed:

# Search for where ENCODED is used
rg -n 'ENCODED' .github/workflows/auto-add-repo.yml -A 5 -B 2

Repository: supermodeltools/supermodeltools.github.io

Length of output: 1152


🏁 Script executed:

# Check if steps.deploy is defined anywhere in the workflow
rg -n 'id:\s*deploy' .github/workflows/auto-add-repo.yml

Repository: supermodeltools/supermodeltools.github.io

Length of output: 118


🌐 Web query:

GitHub Actions environment.url step outputs available timing evaluation

💡 Result:

jobs.<job_id>.environment.name is resolved before the job is sent to a runner (so environment protection rules/approvals can be enforced), which means you can’t rely on step outputs to decide the environment name at runtime. [1]

jobs.<job_id>.environment.url can use the steps context (and also job, runner, env, etc.). [1] However, step outputs only exist after the step has run—the steps context is populated only with steps that have an id and have already completed. [2]

So in practice:

  • environment.url: ${{ steps.deploy.outputs.url }} works only if the deploy step runs earlier in the job and sets that output.
  • You can’t make environment.url depend on outputs from a later step (they won’t exist yet).
  • If the URL comes from another job, pass it via job outputs and use needs.<job_id>.outputs.<name> in environment.url (that context is explicitly allowed there). [1]

Sources

  1. GitHub Docs – Workflow syntax: jobs.<job_id>.environment / .url (allowed contexts; protection rules before runner) (docs.github.com)
  2. GitHub Docs – steps context is only for steps that have already run (docs.github.com)

Citations:


🌐 Web query:

GitHub Actions environment url field steps context order evaluation

💡 Result:

jobs.<job_id>.environment.url can use the steps context (including steps.<id>.outputs.*)—GitHub’s context-availability table explicitly allows steps in jobs.<job_id>.environment.url. [1]

Key implications for evaluation order:

  • The steps context only contains steps that have already run. So your environment.url can only successfully reference outputs from steps that actually executed and produced outputs. [1]
  • In practice, this is why patterns like this work (the URL is derived from a prior step’s output):
    url: ${{ steps.aws-sync.outputs.s3_url }} (where the step has id: aws-sync and writes s3_url=... to $GITHUB_OUTPUT). [2]
  • The environment.url value is then shown as the deployment URL in the GitHub UI (deployments/workflow graph/PR “View deployment”). [3]

Rule of thumb: if you want a dynamic environment URL, compute it in an earlier step (with an id) and write it to $GITHUB_OUTPUT, then reference steps.<id>.outputs.<name> from environment.url. [2]

Sources: GitHub context availability + steps semantics [1], working example using environment.url from step outputs [2], official environment.url behavior/UI placement [3].


Child workflow environment.url references a step output that doesn't exist yet.

The embedded workflow (lines 196–203) has environment.url: ${{ steps.deploy.outputs.page_url }} but the steps.deploy step hasn't run yet—it's the last step at line 212. In GitHub Actions, the steps context only contains outputs from steps that have already executed, so this reference will be undefined or cause an error when the child workflow runs.

Move the deploy step earlier or compute the URL in an earlier step, write it to $GITHUB_OUTPUT with an id, and reference that instead. For example:

-                url: ${{ steps.deploy.outputs.page_url }}
+                # Remove this; environment.url can't reference future steps

Then after actions/deploy-pages@v4 succeeds and outputs the URL, you'd need to either:

  1. Add a step after deploy that explicitly sets the URL (and reference it in a separate workflow run), or
  2. Accept that environment.url will be empty in this workflow and set it via a second job that depends on this one.

Note: The single quotes around WORKFLOW_CONTENT (line 175) correctly protect the ${{ ... }} expressions from being evaluated in the parent workflow, so there's no secret-leakage risk there—the expressions are passed literally to the child workflow as intended.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/auto-add-repo.yml around lines 175 - 216, The child
workflow's environment.url is referencing a step output that doesn't exist yet
(environment.url: ${{ steps.deploy.outputs.page_url }} while the deploy step is
the last step id: deploy using actions/deploy-pages@v4); fix by ensuring the URL
value is produced before it's referenced—either move the deploy step earlier so
steps.deploy runs before the environment block or add a step immediately after
actions/deploy-pages@v4 that captures its output (read the page_url from the
deploy action output and write it to GITHUB_OUTPUT or set a step output with an
id) and then reference that new step id in environment.url instead of
steps.deploy.outputs.page_url; update WORKFLOW_CONTENT accordingly so the child
workflow contains the corrected step ordering or the intermediate output-writing
step.

Homepage changes:
- Add inline submit form below search: paste a GitHub URL, see a
  preview of where docs will live, one click to submit
- Accepts full URLs or owner/repo shorthand
- "No results" area now links to the submit form
- Mobile-responsive layout for the submit row

Sync workflow (sync-repos.yml):
- Runs every 6 hours + manual trigger
- Scans all org repos for arch-docs workflow
- Auto-adds any missing repos to repos.yaml
- Forks → Community category, org-native → Supermodel Open Source
- Auto-detects description, language, pill from GitHub API
- Commits and pushes to trigger homepage rebuild

This ensures repos like volt that are set up internally
but never added to repos.yaml will auto-appear on the homepage.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/sync-repos.yml (1)

77-95: Category writes are order-dependent; prefer selecting by category name

At Lines 81 and 90, writing via categories[1] / categories[0] is brittle. If category order changes in repos.yaml, repos get silently filed under the wrong section.

Suggested refactor
-              yq -i '.categories[1].repos += [{
+              yq -i '(.categories[] | select(.name == "Community").repos) += [{
                 "name": strenv(REPO_NAME),
                 "upstream": strenv(PARENT),
                 "description": strenv(DESCRIPTION),
                 "pill": strenv(PILL),
                 "pill_class": strenv(PILL_CLASS)
               }]' repos.yaml
@@
-              yq -i '.categories[0].repos += [{
+              yq -i '(.categories[] | select(.name == "Supermodel Open Source").repos) += [{
                 "name": strenv(REPO_NAME),
                 "description": strenv(DESCRIPTION),
                 "pill": strenv(PILL),
                 "pill_class": strenv(PILL_CLASS)
               }]' repos.yaml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-repos.yml around lines 77 - 95, The current yq
updates use positional category indexes (categories[1]/categories[0]) which is
brittle; change the yq expressions in the fork and non-fork branches so they
target the category object by name instead of by index (e.g. use a selector like
'.categories[] | select(.name == "Supermodel Open Source").repos' and the
matching community name for forks) when appending the repo entry, keeping the
same environment variables (REPO_NAME, PARENT, DESCRIPTION, PILL, PILL_CLASS)
and preserving the existing JSON object shape; update both yq invocations that
currently reference categories[1] and categories[0] so they append to the
correct category in repos.yaml regardless of order.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/sync-repos.yml:
- Around line 29-55: Change the repo discovery to only public repos and skip
archived repos before persisting metadata: replace the org list query param from
type=all to type=public (the REPOS variable generation using gh api) and after
fetching REPO_JSON check the archived flag (e.g., ARCHIVED=$(echo "$REPO_JSON" |
jq -r '.archived')) and continue if true; ensure you still respect existing fork
checks (IS_FORK) before writing to repos.yaml so private/internal or archived
repositories are never added from REPO_JSON/REPOS to the persisted output.
- Around line 33-35: Replace the fragile regex grep check that looks for name:
${REPO_NAME} with a YAML-aware equality check using yq: instead of if grep -q
"name: ${REPO_NAME}$" repos.yaml; then continue; fi, call yq with the REPO_NAME
as an argument (for example: yq eval --arg name "$REPO_NAME" 'any(.repos[].name
== $name)' repos.yaml) and test for a true/false result to decide whether to
continue; this treats repo names as literal strings and avoids regex
metacharacter issues with names like my.repo.

---

Nitpick comments:
In @.github/workflows/sync-repos.yml:
- Around line 77-95: The current yq updates use positional category indexes
(categories[1]/categories[0]) which is brittle; change the yq expressions in the
fork and non-fork branches so they target the category object by name instead of
by index (e.g. use a selector like '.categories[] | select(.name == "Supermodel
Open Source").repos' and the matching community name for forks) when appending
the repo entry, keeping the same environment variables (REPO_NAME, PARENT,
DESCRIPTION, PILL, PILL_CLASS) and preserving the existing JSON object shape;
update both yq invocations that currently reference categories[1] and
categories[0] so they append to the correct category in repos.yaml regardless of
order.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa6acbf and 1a7a04f.

📒 Files selected for processing (2)
  • .github/workflows/sync-repos.yml
  • generate-index.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • generate-index.go

Comment on lines +29 to +55
REPOS=$(gh api --paginate "orgs/$ORG/repos?per_page=100&type=all" --jq '.[].name')

for REPO_NAME in $REPOS; do
# Skip if already in repos.yaml
if grep -q "name: ${REPO_NAME}$" repos.yaml; then
continue
fi

# Skip the homepage repo itself
if [ "$REPO_NAME" = "supermodeltools.github.io" ]; then
continue
fi

# Check if repo has arch-docs workflow
if ! gh api "repos/$ORG/$REPO_NAME/contents/.github/workflows/arch-docs.yml" &>/dev/null; then
continue
fi

echo "Found unlisted repo with arch-docs: $REPO_NAME"

# Get repo metadata
REPO_JSON=$(gh api "repos/$ORG/$REPO_NAME")
DESCRIPTION=$(echo "$REPO_JSON" | jq -r '.description // "Architecture documentation"' | head -c 200)
LANGUAGE=$(echo "$REPO_JSON" | jq -r '.language // "Unknown"')
IS_FORK=$(echo "$REPO_JSON" | jq -r '.fork')
PARENT=$(echo "$REPO_JSON" | jq -r '.parent.full_name // ""')

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restrict discovery to public/non-archived repos before writing metadata

At Line 29, type=all can pull private/internal repos with this token. Then Lines 50-55 + 81-95 persist metadata to repos.yaml, which risks exposing internal repo names/descriptions publicly.

Suggested fix
-          REPOS=$(gh api --paginate "orgs/$ORG/repos?per_page=100&type=all" --jq '.[].name')
+          REPOS=$(gh api --paginate "orgs/$ORG/repos?per_page=100&type=public" --jq '.[] | select(.archived == false) | .name')

@@
             REPO_JSON=$(gh api "repos/$ORG/$REPO_NAME")
+            IS_PRIVATE=$(echo "$REPO_JSON" | jq -r '.private')
+            IS_ARCHIVED=$(echo "$REPO_JSON" | jq -r '.archived')
+            IS_EMPTY=$(echo "$REPO_JSON" | jq -r '.size == 0')
+            if [ "$IS_PRIVATE" = "true" ] || [ "$IS_ARCHIVED" = "true" ] || [ "$IS_EMPTY" = "true" ]; then
+              continue
+            fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
REPOS=$(gh api --paginate "orgs/$ORG/repos?per_page=100&type=all" --jq '.[].name')
for REPO_NAME in $REPOS; do
# Skip if already in repos.yaml
if grep -q "name: ${REPO_NAME}$" repos.yaml; then
continue
fi
# Skip the homepage repo itself
if [ "$REPO_NAME" = "supermodeltools.github.io" ]; then
continue
fi
# Check if repo has arch-docs workflow
if ! gh api "repos/$ORG/$REPO_NAME/contents/.github/workflows/arch-docs.yml" &>/dev/null; then
continue
fi
echo "Found unlisted repo with arch-docs: $REPO_NAME"
# Get repo metadata
REPO_JSON=$(gh api "repos/$ORG/$REPO_NAME")
DESCRIPTION=$(echo "$REPO_JSON" | jq -r '.description // "Architecture documentation"' | head -c 200)
LANGUAGE=$(echo "$REPO_JSON" | jq -r '.language // "Unknown"')
IS_FORK=$(echo "$REPO_JSON" | jq -r '.fork')
PARENT=$(echo "$REPO_JSON" | jq -r '.parent.full_name // ""')
REPOS=$(gh api --paginate "orgs/$ORG/repos?per_page=100&type=public" --jq '.[] | select(.archived == false) | .name')
for REPO_NAME in $REPOS; do
# Skip if already in repos.yaml
if grep -q "name: ${REPO_NAME}$" repos.yaml; then
continue
fi
# Skip the homepage repo itself
if [ "$REPO_NAME" = "supermodeltools.github.io" ]; then
continue
fi
# Check if repo has arch-docs workflow
if ! gh api "repos/$ORG/$REPO_NAME/contents/.github/workflows/arch-docs.yml" &>/dev/null; then
continue
fi
echo "Found unlisted repo with arch-docs: $REPO_NAME"
# Get repo metadata
REPO_JSON=$(gh api "repos/$ORG/$REPO_NAME")
IS_PRIVATE=$(echo "$REPO_JSON" | jq -r '.private')
IS_ARCHIVED=$(echo "$REPO_JSON" | jq -r '.archived')
IS_EMPTY=$(echo "$REPO_JSON" | jq -r '.size == 0')
if [ "$IS_PRIVATE" = "true" ] || [ "$IS_ARCHIVED" = "true" ] || [ "$IS_EMPTY" = "true" ]; then
continue
fi
DESCRIPTION=$(echo "$REPO_JSON" | jq -r '.description // "Architecture documentation"' | head -c 200)
LANGUAGE=$(echo "$REPO_JSON" | jq -r '.language // "Unknown"')
IS_FORK=$(echo "$REPO_JSON" | jq -r '.fork')
PARENT=$(echo "$REPO_JSON" | jq -r '.parent.full_name // ""')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-repos.yml around lines 29 - 55, Change the repo
discovery to only public repos and skip archived repos before persisting
metadata: replace the org list query param from type=all to type=public (the
REPOS variable generation using gh api) and after fetching REPO_JSON check the
archived flag (e.g., ARCHIVED=$(echo "$REPO_JSON" | jq -r '.archived')) and
continue if true; ensure you still respect existing fork checks (IS_FORK) before
writing to repos.yaml so private/internal or archived repositories are never
added from REPO_JSON/REPOS to the persisted output.

Comment on lines +33 to +35
if grep -q "name: ${REPO_NAME}$" repos.yaml; then
continue
fi
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the sync-repos.yml file
find . -name "sync-repos.yml" -type f

Repository: supermodeltools/supermodeltools.github.io

Length of output: 119


🏁 Script executed:

# Also look for repos.yaml
find . -name "repos.yaml" -type f

Repository: supermodeltools/supermodeltools.github.io

Length of output: 97


🏁 Script executed:

# Read the sync-repos.yml file to see the context around lines 33-35
cat -n .github/workflows/sync-repos.yml | head -50

Repository: supermodeltools/supermodeltools.github.io

Length of output: 1750


🏁 Script executed:

# Read the repos.yaml file to see what repo names actually exist
cat -n repos.yaml

Repository: supermodeltools/supermodeltools.github.io

Length of output: 7687


Switch to YAML-aware duplicate detection (grep with regex is fragile)

The current grep approach at line 33 treats repo names as regex patterns. While today's repo names are safe (no dots or regex metacharacters), this is a ticking time bomb: if someone adds a repo like my.repo, the dot becomes a regex wildcard matching any character, causing false positives or missed duplicates.

The yq approach below is the right fix—it's YAML-aware and handles repo names as literal strings:

Suggested fix
-            if grep -q "name: ${REPO_NAME}$" repos.yaml; then
+            export REPO_NAME
+            if yq -e '.categories[].repos[] | select(.name == strenv(REPO_NAME))' repos.yaml >/dev/null; then
               continue
             fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-repos.yml around lines 33 - 35, Replace the fragile
regex grep check that looks for name: ${REPO_NAME} with a YAML-aware equality
check using yq: instead of if grep -q "name: ${REPO_NAME}$" repos.yaml; then
continue; fi, call yq with the REPO_NAME as an argument (for example: yq eval
--arg name "$REPO_NAME" 'any(.repos[].name == $name)' repos.yaml) and test for a
true/false result to decide whether to continue; this treats repo names as
literal strings and avoids regex metacharacter issues with names like my.repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add 'Request a Repo' feature to the repos homepage

1 participant