Skip to content

feat(provisioning): Hybrid owned, GitHub-native provisioning + accessible companion#230

Merged
accesswatch merged 4 commits into
mainfrom
feature/hybrid-owned-provisioning
Jun 2, 2026
Merged

feat(provisioning): Hybrid owned, GitHub-native provisioning + accessible companion#230
accesswatch merged 4 commits into
mainfrom
feature/hybrid-owned-provisioning

Conversation

@accesswatch

Copy link
Copy Markdown
Collaborator

Delivers Hybrid owned provisioning system with GitHub-native workflow orchestration and optional Flask companion for accessibility.

Changes

  • GitHub-native provisioning (replaces Classroom dependency)
  • Owned roster management (roster.json contract)
  • Accessible Flask companion app
  • Comprehensive deployment and operator guides
  • All automation and provisioning tests passing

Deployment

Tests passing:

  • automation-tests: 98/98
  • provisioning-tests: 55/55

Ready for production deployment.

GitHub Workshop Bot and others added 4 commits June 1, 2026 14:18
…g + accessible companion

Implements the Hybrid plan (Option C) from golden.md and SPEC.md: a dependable
GitHub-native core that replaces GitHub Classroom provisioning, plus an optional,
fully accessible Flask companion at the edges.

Owned core (no third-party npm deps; built-in crypto + fetch):
- roster.js + roster.schema.json: owned roster of record (parse/validate/upsert/
  serialize/redact), keyed on (github_handle, cohort_id)
- progress.js: owned progress derived from deterministic signals (ack,
  day1-complete, labels, closed challenge issues, PR closing keywords)
- github-app-auth.js: RS256 App JWT + short-lived installation token minting
- github-client.js: minimal GitHub REST client (fetch + Octokit adapters)
- provision-core.js: idempotent, serial, backoff provisioning algorithm with
  self-healing and loud failure (SPEC 7.2b)
- provision-cli.js + provision-learning-rooms.yml: runner and scheduled/manual
  workflow supporting github-app and actions-bot modes

Optional accessible companion (companion/):
- Flask app: accessible registration front door + facilitator dashboard that
  read/write the same owned roster contract; non-critical by design
- WCAG 2.2 AA templates and OWASP-aware controls (CSRF, auth with constant-time
  compare, input validation, rate limiting, CSP/security headers)

Docs and tests:
- admin/OWNED_PROVISIONING.md operator guide; companion/README.md; example roster;
  golden.md and SPEC.md committed as canonical vision/spec with source maps
- 55 Node tests (npm run test:provisioning) + 25 Python tests; both wired into
  the automation-tests workflow

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Step-by-step deployment for the owned, GitHub-native provisioning core and the optional Flask companion: admin roster repo, GitHub App creation with least-privilege permissions, variables/secrets, smoke test with idempotency proof, companion deployment, go-live checklist, and rollback/fallback. Cross-linked from OWNED_PROVISIONING.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Single entry point cataloging every part of the Hybrid deliverable (planning docs, provisioning core, companion, CI wiring, tests) with links and a suggested review order. Functional files stay in their conventional locations; the index points to them. Cross-linked from the deployment and operator guides.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add html/ equivalents for the Hybrid plan markdown (golden, SPEC, review index, deployment guide, owned provisioning, cohort provisioning, and companion README) via the repo's build:html pipeline. Internal .md links are rewritten to .html. Excludes companion/.venv build artifacts and unrelated full-site churn.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 2, 2026 19:08
@accesswatch
accesswatch requested a review from taylorarndt as a code owner June 2, 2026 19:08
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Peer Review Assigned

Hi @accesswatch! Your PR has been automatically paired with @taylorarndt for peer review.

For @taylorarndt:

This is a great opportunity to practice code review skills! Here's what to look for:

Content Quality:

  • Does the change accomplish what the issue describes?
  • Is the writing clear and helpful?
  • Are there any typos or grammar issues?

Accessibility:

  • Proper heading hierarchy (H1 → H2 → H3, no skips)?
  • Descriptive link text (not "click here")?
  • Alt text on images?
  • [TODO] markers removed?

Documentation:

  • Code blocks are properly formatted?
  • Tables have headers?
  • References/links work correctly?

Review Guidelines:

  • Be kind and constructive
  • Suggest improvements, don't just point out problems
  • Ask questions if something is unclear
  • Approve when ready or request changes with explanation

Resources:


Pairing by Learning Room Grouping Engine

@accesswatch
accesswatch merged commit 838a130 into main Jun 2, 2026
5 checks passed
@accesswatch
accesswatch deleted the feature/hybrid-owned-provisioning branch June 2, 2026 19:10

Copilot AI 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.

Pull request overview

This PR introduces the Hybrid “owned provisioning” architecture for GIT Going with GitHub (GLOW): a GitHub-native provisioning core (as a replacement path for GitHub Classroom) plus an optional accessibility-focused Flask companion that reads/writes the same owned roster.json contract.

Changes:

  • Adds an owned roster contract (roster.schema.json) and provisioning implementation (Node scripts + new scheduled/manual GitHub Actions workflow).
  • Adds an optional Flask companion app (registration front door + facilitator dashboard) with tests and CI wiring.
  • Adds operator/deployment documentation (plus generated HTML equivalents) describing the Hybrid plan and operational procedures.

Reviewed changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
roster.schema.json Adds JSON Schema for the owned roster-of-record contract.
package.json Adds test:provisioning script to run provisioning unit tests.
html/golden.html Generated HTML for the new Hybrid vision doc.
html/companion/index.html Generated HTML for companion documentation landing page.
html/admin/OWNED_PROVISIONING.html Generated HTML operator guide for owned provisioning.
html/admin/HYBRID_REVIEW_INDEX.html Generated HTML review index for the Hybrid deliverable.
html/admin/HYBRID_DEPLOYMENT_GUIDE.html Generated HTML deployment guide for Hybrid architecture.
html/admin/COHORT_PROVISIONING.html Generated HTML updated to reference owned provisioning path.
golden.md Adds Hybrid plan vision/decision record (“golden” north star).
companion/tests/test_roster_store.py Unit tests for the companion’s roster store/contract.
companion/tests/test_app.py Unit tests for companion routes, CSRF, headers, auth, and rate limiting.
companion/templates/register.html Accessible registration form template with error summary.
companion/templates/register_success.html Registration confirmation template.
companion/templates/login.html Facilitator sign-in template.
companion/templates/error.html Error page template for 400/404/429 flows.
companion/templates/dashboard.html Read-only facilitator dashboard template rendering the roster.
companion/templates/base.html Base layout with navigation, skip link, and flash live region.
companion/static/styles.css Companion accessibility-first CSS (focus styles, contrast, layout).
companion/roster_store.py Python implementation of the owned roster contract for the companion.
companion/requirements.txt Declares Flask dependency range.
companion/README.md Companion overview and run/security/accessibility guidance.
companion/app.py Flask app implementation: routes, CSRF, headers, auth, and rate limiting.
companion/.gitignore Prevents committing local env/instance/bytecode artifacts.
admin/OWNED_PROVISIONING.md Operator guide for the owned provisioning subsystem.
admin/HYBRID_REVIEW_INDEX.md Central index for reviewing all Hybrid plan deliverables.
admin/HYBRID_DEPLOYMENT_GUIDE.md Step-by-step deployment and verification guide for Hybrid architecture.
admin/examples/roster.example.json Example roster JSON illustrating the owned contract.
admin/COHORT_PROVISIONING.md Adds forward-looking note linking to owned provisioning docs.
.github/workflows/provision-learning-rooms.yml New scheduled/manual workflow to provision student repos from roster.
.github/workflows/automation-tests.yml Extends CI to run provisioning tests and companion Python tests.
.github/scripts/provisioning/roster.js Node roster contract: parse/validate/upsert/serialize/redact.
.github/scripts/provisioning/provision-core.js Idempotent serial provisioning algorithm with backoff and verification.
.github/scripts/provisioning/provision-cli.js CLI runner for provisioning (GitHub App or PAT “actions-bot” mode).
.github/scripts/provisioning/progress.js Deterministic progress/status derivation from controlled signals.
.github/scripts/provisioning/github-client.js Minimal GitHub REST client for provisioning operations.
.github/scripts/provisioning/github-app-auth.js Node crypto GitHub App JWT + installation-token minting.
.github/scripts/provisioning/tests/roster.test.js Node tests for roster contract behavior.
.github/scripts/provisioning/tests/provision-core.test.js Node tests for provisioning algorithm/idempotency/backoff.
.github/scripts/provisioning/tests/provision-cli.test.js Node tests for CLI arg parsing and token resolution.
.github/scripts/provisioning/tests/progress.test.js Node tests for progress derivation and signal parsing.
.github/scripts/provisioning/tests/github-client.test.js Node tests for fetch client + Octokit adapter.
.github/scripts/provisioning/tests/github-app-auth.test.js Node tests for JWT creation and installation-token minting.

Comment on lines +33 to +41
async function request(method, path, body) {
const res = await fetchImpl(`${apiBaseUrl}${path}`, {
method,
headers: {
Authorization: `token ${token}`,
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': userAgent,
...(body ? { 'Content-Type': 'application/json' } : {})
Comment on lines +24 to +28
function isSecondaryRateLimit(err) {
if (!err) return false;
if (err.status === 403 || err.status === 429) return true;
return /HTTP (403|429)/.test(String(err.message || ''));
}
Comment on lines +192 to +195
let templateSha = null;
if (typeof client.getDefaultBranchSha === 'function') {
templateSha = await client.getDefaultBranchSha({ owner: studentOwner, repo: repoName });
}
Comment thread companion/app.py
Comment on lines +227 to +231
target = request.args.get("next") or url_for("dashboard")
# Only allow local redirects.
if not target.startswith("/"):
target = url_for("dashboard")
return redirect(target)
/>
</div>

<fieldset class="field">
Comment thread companion/roster_store.py
Comment on lines +76 to +95
learners = data.get("learners")
if not isinstance(learners, list):
raise RosterError("Roster.learners must be a list")
seen = set()
for learner in learners:
problems = validate_learner(learner)
if problems:
raise RosterError(
f"Invalid learner {learner.get('github_handle')}: {'; '.join(problems)}"
)
key = learner_key(learner["github_handle"], learner["cohort_id"])
if key in seen:
raise RosterError(f"Duplicate learner for key {key}")
seen.add(key)
return Roster(
version=1,
cohorts=data.get("cohorts", []) or [],
learners=learners,
generated_at=data.get("generated_at"),
)
Comment thread companion/roster_store.py
Comment on lines +119 to +122
existing = self.find(candidate["github_handle"], candidate["cohort_id"])
if existing is not None:
existing.update({k: v for k, v in entry.items() if v is not None})
return existing
</div>
{% endif %}

<form method="post" action="{{ url_for('login') }}{% if request.args.get('next') %}?next={{ request.args.get('next') }}{% endif %}" novalidate>
Comment on lines +50 to +58
- name: Run provisioning test suite
run: npm run test:provisioning

- name: Install companion dependencies
run: pip install -r companion/requirements.txt

- name: Run companion test suite
working-directory: companion
run: python -m unittest discover -s tests
Comment on lines +53 to +55
- name: Install companion dependencies
run: pip install -r companion/requirements.txt

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.

2 participants