Sitelet https://github.com/Resnovas/.github/pull/12
Skip to content

feat(house): Actions permissions in the house preset - #12

Merged
TGTGamer merged 2 commits into
mainfrom
claude/smc-63-more-settings
Sep 26, 2026
Merged

TGTGamer merged 2 commits into
mainfrom
claude/smc-63-more-settings

Conversation

@TGTGamer

@TGTGamer TGTGamer commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

The house preset now sets GitHub Actions through smartcloud's new settings.actions section (Resnovas/smartcloud#644):

  • workflowPermissions: read: the workflow token is read-only by default. Every workflow in the org already declares its permissions; I checked each repository before choosing this.
  • createPullRequests: true: the Graphify refresh falls back to the workflow token where ACCESS_TOKEN is unavailable, and it has to be able to open its pull request.
  • accessLevel: organization: a private repository's reusable workflows stay callable from the rest of the organisation. This is the setting whose loss broke house-graphify. Public repositories have no access level, and smartcloud skips it there with a notice.

GOVERNANCE.md (root and template) lists the new baseline. The README says the access level must be set by hand once when this repository becomes private, because the workflows that would apply it cannot run until it is set.

Checks: the node --test suite, the render check and the surfaces check all pass locally, and the preset validates with the smartcloud CLI from #644.

Stacks on #11 (SMC-62).

Closes SMC-63


Note

Medium Risk
Changes org-wide GitHub Actions token defaults and elevates Graphify refresh job permissions when falling back to the workflow token; behaviour is intentional but affects CI on every house-managed repository.

Overview
Adds GitHub Actions baseline to the house smartcloud preset: read-only workflow tokens by default, PR creation still allowed, and organisation-wide access to reusable workflows on private repos (settings.actions in smartcloud/house.yml). GOVERNANCE and the README describe the new baseline and the one-time manual Actions access step when this repo is private.

Graphify no longer skips the default-branch refresh when ACCESS_TOKEN is missing. The reusable workflow’s refresh job requests contents and pull-requests write, uses secrets.token || github.token for create-pull-request, and drops the “skipped without token” notice. house-graphify caller permissions are raised so the refresh path can push and open PRs under the workflow token fallback.

Reviewed by Cursor Bugbot for commit 209902f. Bugbot is set up for automated code reviews on this repo. Configure here.

@linear-code

linear-code Bot commented Sep 26, 2026

Copy link
Copy Markdown

SMC-63

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Configure GitHub Actions permissions in the house preset

✨ Enhancement ⚙️ Configuration changes 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Configure read-only workflow tokens while allowing Graphify to create pull requests.
• Share private repositories' reusable workflows across the organization through smartcloud.
• Document the Actions baseline and private-repository bootstrap requirement.
Diagram

graph TD
  Preset["House preset"] --> Sync["smartcloud sync"] --> Actions["Actions settings"] --> Token["Workflow token"] --> Graphify["Graphify refresh"]
  Actions --> Sharing["Reusable workflows"]
Loading
High-Level Assessment

The declarative house preset is the appropriate source of truth because smartcloud can consistently enforce these settings and prevent repository drift. Fully manual configuration was considered but is only necessary for the documented one-time private-repository bootstrap.

Files changed (4) +13 / -1

Documentation (3) +4 / -1
GOVERNANCE.mdAdd Actions permissions to the governance baseline +1/-0

Add Actions permissions to the governance baseline

• Documents read-only workflow tokens, pull-request creation, and organization-wide reusable workflow access as standard repository governance.

GOVERNANCE.md

README.mdDocument private repository Actions bootstrap +2/-1

Document private repository Actions bootstrap

• Clarifies that organization Actions access applies while this repository is private. Explains that the setting must be enabled manually once before reusable workflows can enforce it.

README.md

GOVERNANCE.mdPropagate the Actions governance baseline +1/-0

Propagate the Actions governance baseline

• Adds the GitHub Actions permission and reusable workflow sharing policy to the governance template synchronized into managed repositories.

templates/GOVERNANCE.md

Other (1) +9 / -0
house.ymlConfigure house-wide GitHub Actions permissions +9/-0

Configure house-wide GitHub Actions permissions

• Adds smartcloud Actions settings for read-only default workflow permissions, workflow-token pull-request creation, and organization access to private repositories' reusable workflows.

smartcloud/house.yml

@qodo-code-review

qodo-code-review Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Graph refresh pull requests fail ✗ Dismissed 🔴 Required 🐞 Bug ≡ Correctness
Description
The new createPullRequests setting enables repository-level pull-request creation but leaves
Graphify's fallback token without contents: write and pull-requests: write. When ACCESS_TOKEN
is unavailable and secrets.token || github.token selects the workflow token, the caller grants
only read access while the reusable refresh job inherits an empty permission set, so branch pushing
and pull-request creation fail.
Code

smartcloud/house.yml[205]

+    createPullRequests: true
Evidence
The refresh action explicitly falls back to github.token, but the caller permits only `contents:
read`, and the called workflow defaults jobs to no permissions without adding write permissions to
refresh. GitHub documents that permissions passed into reusable workflows cannot be elevated
downstream, while the create-pull-request action requires both contents: write and `pull-requests:
write` in addition to enabling pull-request creation in repository settings.

smartcloud/house.yml[198-206]
templates/.github/workflows/house-graphify.yml[18-25]
.github/workflows/graphify.yml[21-25]
.github/workflows/graphify.yml[43-47]
.github/workflows/graphify.yml[70-74]
🌐 GitHub states that token permissions passed from a reusable workflow's caller can only be downgraded, not elevated.
🌐 The action documents that a workflow-token invocation needs explicit contents: write and pull-requests: write permissions as well as the repository setting that permits Actions to create pull requests.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Enabling `settings.actions.createPullRequests` does not grant the workflow token the API scopes needed by Graphify. The reusable workflow caller and refresh job must both permit content writes and pull-request writes.

## Fix Focus Areas
- templates/.github/workflows/house-graphify.yml[18-25]
- .github/workflows/house-graphify.yml[18-25]
- .github/workflows/graphify.yml[43-47]

## Recommended Fix
Grant `contents: write` and `pull-requests: write` to the reusable-workflow calling job in both the template and rendered workflow. Explicitly grant the same permissions to Graphify's `refresh` job; retain the check job's existing read-only override so pull-request checks remain restricted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

No findings for this group


Informational

No findings for this group

Grey Divider

Context sources
✅ Compliance rules (platform): 1 rule
✅ Web pages:
  +7 more
Review mode: ⚖️ Balanced: This changes organization-wide GitHub Actions permissions and private reusable-workflow access through runtime configuration, creating meaningful security and availability risk despite the small diff.

Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread smartcloud/house.yml

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

Risk: high. Left a non-blocking comment; no reviewers assigned. Cursor Bugbot and Cursor Security Agent completed with no findings, but this house-wide Actions permission change is above the medium approval threshold and needs human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

TGTGamer added a commit to Resnovas/smartcloud that referenced this pull request Sep 26, 2026
Matches Resnovas/.github#12, where the refresh job gets the write access it
needs when it falls back to the workflow token.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

Risk: high. Left a non-blocking comment; no reviewers assigned. Cursor Security Agent completed with no findings and Bugbot was not present, but this house-wide Actions permission change is above the medium approval threshold and needs human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@TGTGamer
TGTGamer added this pull request to stack #23 September 26, 2026 22:47
Base automatically changed from claude/smc-62-least-privilege to main September 26, 2026 23:34
The preset now sets GitHub Actions through smartcloud: a read-only
workflow token by default (every house workflow declares its
permissions), which may still open pull requests for the Graphify
refresh's fallback, and on private repositories an organisation access
level, the setting whose loss broke house-graphify. GOVERNANCE.md and
the README describe it.

Refs SMC-63

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>
…flow token

The house preset allows the workflow token to create pull requests so the
Graphify refresh can fall back to it, but the caller granted only
contents: read and the refresh job declared nothing. The caller now sets
contents and pull-requests write as the ceiling, and the refresh job asks
for both; the check job stays read-only.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>
@TGTGamer
TGTGamer force-pushed the claude/smc-63-more-settings branch from e31de7b to 209902f Compare September 26, 2026 23:35
@TGTGamer

Copy link
Copy Markdown
Member Author

Rebased onto main after #11 and #20 landed (209902f). Two conflicts, both kept:

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

Makes the Graphify refresh fall back to the workflow token when ACCESS_TOKEN is unset — it now pushes house/graphify and opens the refresh pull request instead of skipping with a notice — which requires the called workflow and its caller to grant contents: write and pull-requests: write. Adds an actions settings block to house.yml that keeps the workflow token read-only by default (workflowPermissions: read), allows it to create pull requests (createPullRequests: true), and sets accessLevel: organization so private repositories stay callable across the org. Documents that this access level must be set by hand once when a repo goes private, since the reusable workflows that apply the preset can't run until it is.

Worth a look

  • Write-capable GitHub token is passed to a mutable third-party action tag — .github/workflows/graphify.yml · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 72 functions depend on the 72 functions this change touches.

Health — grade A; no new coupling hotspots.

Verification — 72 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 72 function(s) in the blast radius were not formally verified this run

@TGTGamer
TGTGamer merged commit 983df67 into main Sep 26, 2026
11 of 14 checks passed
@TGTGamer
TGTGamer deleted the claude/smc-63-more-settings branch September 26, 2026 23:44

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Risk: high. Left a non-blocking comment; no reviewers assigned. Cursor Bugbot completed with no findings, but Cursor Security Agent did not finish within 8 minutes, and this house-wide Actions permission change is above the medium approval threshold and needs human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

TGTGamer added a commit to Resnovas/smartcloud that referenced this pull request Sep 26, 2026
Matches Resnovas/.github#12, where the refresh job gets the write access it
needs when it falls back to the workflow token.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>
TGTGamer added a commit to Resnovas/smartcloud that referenced this pull request Sep 27, 2026
#644)

* feat(settings): Actions, access, webhooks, Pages and variables as code

The settings section now also covers GitHub Actions permissions (allowed
actions, SHA pinning, the workflow token's default permissions and
whether it may open pull requests, and the access level that decides
which private repositories may call this one's reusable workflows),
collaborators and teams, webhooks, the Pages site, and a check that
required Actions variables exist, by name only.

Teams go through GraphQL's updateTeamsRepository so every call stays
bound to the repository. Webhooks are matched by URL, their config is
patched on its own endpoint so a secret set by hand survives, and
reports name only the host. The access level exists only for private
repositories, so on a public one it is skipped with a notice.

Refs SMC-63

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* fix(dry-run): keep only the origin of URLs in recorded request bodies

A webhook URL can carry a token in its path or query, and dry-run output
printed the recorded POST /hooks body in full. The recorder now keeps only
the URL's origin, matching the host-only webhook descriptions in the plan.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* fix(config): reject webhook URLs that do not parse

The pattern accepted values such as http://[ that only fail once GitHub
is called. A URL.canParse filter now rejects them when the config loads;
the JSON schema is unchanged.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* ci(house): sync the Graphify caller's write permissions

Matches Resnovas/.github#12, where the refresh job gets the write access it
needs when it falls back to the workflow token.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* fix(settings): enforce Pages HTTPS in its own call after the domain

GitHub refuses https_enforced until the custom domain has a certificate,
which is issued only once the domain is stored. Sending both in one PUT
meant a first-time config never stored the domain; now the domain is set
first and HTTPS is enforced on a later run if not yet possible.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* fix(settings): redact dry-run webhook URLs with a password or fragment

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* fix(settings): ignore a Pages branch and path on a workflow site

A workflow-built site has no source, but a config setting buildType:
workflow with a branch or path sent both build_type workflow and a source.
The branch and path are now ignored for a workflow site.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

* fix(config): keep a rejected webhook URL out of the decode error

A webhook URL that failed the pattern or did not parse was repeated in the
config error, so a token in it reached logs. Both checks now report a fixed
message.

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>

---------

Signed-off-by: Jonathan Stevens <jonathan@resnovas.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant