Add 'Request a Repo' button and issue template#3
Conversation
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
WalkthroughAdds 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 Changes
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
- 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)
There was a problem hiding this comment.
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).
| - 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 |
There was a problem hiding this comment.
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.
| - 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.
| if: contains(github.event.issue.labels.*.name, 'repo-request') | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| issues: write | ||
| env: |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find and examine the workflow file
find . -name "auto-add-repo.yml" -type fRepository: 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 -20Repository: 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 likeissues/issue_commentcan have higher impact thanpull_requestif 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., viaprintenv, 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_requestworkflows 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_associationto beMEMBER/OWNER, or require a maintainer “approval” action before any secret-using job runs). - Avoid privileged triggers like
pull_request_targetunless 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:
- 1: https://docs.github.com/en/enterprise-server%403.15/actions/reference/events-that-trigger-workflows?utm_source=openai
- 2: https://securitylab.github.com/resources/github-actions-untrusted-input/?utm_source=openai
- 3: https://github.blog/security/supply-chain-security/four-tips-to-keep-your-github-actions-workflows-secure/?utm_source=openai
- 4: https://wellarchitected.github.com/library/application-security/recommendations/actions-security/?utm_source=openai
🌐 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_TOKENusage/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_requestlabeled(orissueslabeled) and requirelabel.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.ymlRepository: 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.
| # 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 |
There was a problem hiding this comment.
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.
| # 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.
| 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) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd .github/workflows && ls -la auto-add-repo.ymlRepository: supermodeltools/supermodeltools.github.io
Length of output: 152
🏁 Script executed:
cat -n .github/workflows/auto-add-repo.yml | head -220 | tail -60Repository: 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 2Repository: 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.ymlRepository: 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 thedeploystep runs earlier in the job and sets that output.- You can’t make
environment.urldepend 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>inenvironment.url(that context is explicitly allowed there). [1]
Sources
- GitHub Docs – Workflow syntax:
jobs.<job_id>.environment/.url(allowed contexts; protection rules before runner) (docs.github.com) - GitHub Docs –
stepscontext is only for steps that have already run (docs.github.com)
Citations:
- 1: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions?text=For+more+information%2C+see+%22GitHub%27s+products.%22&utm_source=openai
- 2: https://docs.github.com/en/enterprise-server%403.17/actions/reference/accessing-contextual-information-about-workflow-runs?utm_source=openai
🌐 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
stepscontext only contains steps that have already run. So yourenvironment.urlcan 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 hasid: aws-syncand writess3_url=...to$GITHUB_OUTPUT). [2] - The
environment.urlvalue 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 stepsThen after actions/deploy-pages@v4 succeeds and outputs the URL, you'd need to either:
- Add a step after deploy that explicitly sets the URL (and reference it in a separate workflow run), or
- Accept that
environment.urlwill 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.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
.github/workflows/sync-repos.yml (1)
77-95: Category writes are order-dependent; prefer selecting by category nameAt Lines 81 and 90, writing via
categories[1]/categories[0]is brittle. If category order changes inrepos.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
📒 Files selected for processing (2)
.github/workflows/sync-repos.ymlgenerate-index.go
🚧 Files skipped from review as they are similar to previous changes (1)
- generate-index.go
| 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 // ""') | ||
|
|
There was a problem hiding this comment.
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.
| 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.
| if grep -q "name: ${REPO_NAME}$" repos.yaml; then | ||
| continue | ||
| fi |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and examine the sync-repos.yml file
find . -name "sync-repos.yml" -type fRepository: supermodeltools/supermodeltools.github.io
Length of output: 119
🏁 Script executed:
# Also look for repos.yaml
find . -name "repos.yaml" -type fRepository: 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 -50Repository: 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.yamlRepository: 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.
This reverts commit 676f876.
Summary
End-to-end self-service repo onboarding — from paste to published.
User-facing: Inline submit form on the homepage
owner/repo) into the form below the search boxrepos.supermodeltools.com/{name}/"Automation: Issue-triggered pipeline (
auto-add-repo.yml)When an issue with
repo-requestlabel is created:supermodeltoolsorgSUPERMODEL_API_KEYsecret, pushesarch-docs.ymlworkflow, enables Pagesrepos.yaml→ homepage auto-rebuildsAutomation: Org-wide sync (
sync-repos.yml)Runs every 6 hours (+ manual trigger). Catches repos set up internally that were never added to the homepage:
arch-docs.ymlworkflowrepos.yamlThis 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
BOT_TOKENrepo+admin:orgscope — fork repos, set secrets, push workflows, push commits that trigger other workflowsSUPERMODEL_API_KEYFiles changed
generate-index.go.github/ISSUE_TEMPLATE/request-repo.yml.github/workflows/auto-add-repo.yml.github/workflows/sync-repos.ymlCloses supermodeltools/arch-docs#13
Test plan
go run generate-index.gobuilds successfullyBOT_TOKEN+SUPERMODEL_API_KEYsecretsSummary by CodeRabbit
New Features
Chores / Automation