Local hosting - #97
Merged
Merged
Conversation
- Implement health check page for site administration with detailed reports on course integrations. - Create user management interface allowing admins to add, edit, and delete users, as well as manage course assignments. - Introduce no-access page for users without course assignments. - Develop shared health chain component to visualize integration statuses. - Add corresponding styles for new components and pages.
- Implemented assignments.html for displaying and managing assignments. - Created assignments.scss for styling the assignments page. - Developed assignments.ts to handle assignment logic, including creation, editing, and loading assignments. - Added invite.html for students to accept assignments via invite links. - Created invite.scss for styling the invite acceptance page. - Developed invite.ts to manage the invite acceptance flow and GitHub username input. - Implemented my-assignments.html to display a student's repositories across courses. - Created my-assignments.scss for styling the student's assignments page. - Developed my-assignments.ts to handle loading and resending invitations for student repositories.
….config for server configuration - Created initial migration for database schema including tables for users, roles, courses, assignments, and related entities. - Implemented unit tests for user Neptun code validation in UsersAdminController, ensuring uniqueness and proper handling of blank values. - Added web.config to configure ASP.NET Core hosting settings and error handling.
…al trigger options
- Implemented CheckTemplate endpoint in AssignmentsController for real-time validation of template repository names during assignment creation. - Added CheckTemplateRequest DTO to facilitate the request structure. - Updated AssignmentsClient to include checkTemplate method for API interaction. - Enhanced CourseAssignments component to verify template status after assignment save, displaying any issues to the user. - Introduced a new GitHub setup help page for guiding users through GitHub App registration and configuration. - Improved UI in course editor and user management sections, including password generation and token management features.
Adds Octokit to Ahk.Web.Services and introduces ICourseGitHubClientFactory as the single place the portal builds an authenticated GitHub client, ahead of porting github-monitor's handlers (which are written against Octokit's payload types and API surface). GitHubRepositoryService is rewritten on top of it. The interface and its four record projections are deliberately unchanged: they keep Octokit's models out of the domain, and they are what lets AssignmentInviteTests mock the service strictly - that suite is the regression net for this rewrite and still passes untouched. The named "github" HttpClient stays, but only for CourseGitHubAppTokenProvider's App-JWT bootstrap and the health checks. Converting the token provider would change the shape of the permissions dictionary GitHubAppInstallationHealthCheck reads, for no gain. Two Octokit 14 details worth recording: NewRepositoryFromTemplate has no IncludeAllBranches property (GitHub defaults it to false, which is what we want), and Repository.IsTemplate / RepositoryInvitation.Expired are non-nullable bool. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ports github-monitor's webhook receiver and all ten of its handlers into the portal, so the reserved path stops answering 405 from the SPA fallback. The six Azure Storage queues are gone with it: the status-tracking handlers call ISubmissionEventService and the chatops handlers call IGradeService in-process, both of which already existed with no callers. Structural changes from the original, everything else verbatim (the bilingual warning strings are a student-facing interface): - Handlers are scoped DI registrations behind IGitHubWebhookHandler rather than reflectively activated types. ActivatorUtilities only ever existed to hand the Function's per-invocation ILogger to a handler. Registration order is the dispatch order and is kept identical. - Per-delivery state (course, delivery id, body, client, run threshold) moved onto GitHubWebhookContext, so handlers hold none. - ActionWorkflowRunHandler's threshold was a const 5 because a deployment served one course; it now reads CourseGitHubConfig.WorkflowRunThreshold. - The workflow payload types move out of `namespace Octokit` into our own. The day Octokit ships its own WorkflowRunEventPayload, that trick stops the build for reasons nobody would connect to this file. The load-bearing design point is that the webhook secret is per course, and the only thing identifying the course is repository.full_name inside the body - so an untrusted body must be parsed before it can be verified. Everything before the signature check is kept inert: one property read from a JsonDocument that is then dropped, two indexed reads, no writes, no GitHub calls, no body logging. A forged name just selects a different course's secret and fails the same 400. Benign cases (repo in no course, integration off) answer 202, not 4xx: GitHub colours non-2xx red in the delivery log, and during cutover an organization legitimately contains repositories that are not a course. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ation-result Ports grade-management's evaluation-result function, the last of the three write-side entry points. HmacSha256Validator, the DTO and the validation order are verbatim ports: publish-results-pr is a Go client running inside student repositories that are updated on their own schedule, so this is a wire contract, and the error strings end up in student build logs. Two things deliberately left as they are rather than "fixed": - Unknown JSON members stay tolerated. The Go client sends imageFiles, which has never had a counterpart here. - [Required] on the nested taskName is not actually enforced, because Validator.TryValidateObject does not recurse into collections. Enforcing it would start failing student builds that pass today. New in the portal: the course comes from the callback token - the authenticated credential - not from the caller-supplied repository name. A mismatch between the two is logged as a warning rather than rejected, since it means a course is using another course's token and the grade is about to land in the wrong place. IDateTimeProvider is replaced by TimeProvider, registered in Program.cs, so the ten-minute clock-skew window stays testable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
201 tests pass, up from 81. Also hardens two things the port inherited. Parity suites, ported case-for-case from the Azure Functions so the portal provably accepts what they accepted: the ahk-monitor.yml grammar, the /ahk ok grammar (including that the last matching line wins - the parse loop's missing break is behaviour, not a bug), and the X-Hub-Signature-256 vectors. HmacSha256ValidatorTests carries the three golden vectors that exist identically in grade-management's suite AND in publish-results-pr's Go tests. Reproducing those base64 strings is the proof the portal is wire-compatible with evaluator containers already running in student repositories, which cannot be redeployed on our schedule. WebhookHandlerRegistrationTests turns the delivery-id invariant into a build failure: GitHubDeliveryId is globally unique but a delivery fans out to several handlers, so at most one handler per event may write a status event. Break that and rows vanish into the redelivery guard - in production, silently. Endpoint tests pin the full response contract of both routes, including that neither returns 401 (proving [AllowAnonymous] works because Program.cs has no fallback policy), and that a body signed with another course's secret is indistinguishable from any other bad signature - which is what contains the parse-before-verify ordering. Two security fixes from review of the previous commits, neither changing which requests are accepted: - Both validators compared signatures with string.Equals, which returns at the first differing character and lets a forged signature be refined a character at a time by timing. Now CryptographicOperations.FixedTimeEquals. - The CI callback logged the caller's token in full at Information level, as grade-management did, putting working credentials into shipped logs. Now masked to a last-four hint, matching the admin API's convention. Octokit models in tests are built by deserializing the JSON GitHub would send rather than through their constructors, which are long and mostly irrelevant. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
github-app.md was actively misleading: it told administrators to point the App's webhook at github-monitor because the portal's receiver did not exist. That instruction is what produced the 405s this work started from. It now documents the real URL, that the webhook secret is per course, the five subscribed events, and a per-course cutover checklist. New: a "Delivery responses" table explaining what each status means when read in Advanced -> Recent Deliveries, since that page is the only diagnostic surface GitHub offers. Troubleshooting gains the three symptoms actually hit while debugging - 405 with Allow: GET, HEAD (URL points at the SPA fallback), 200 with nothing happening (repo not opted in), and no deliveries at all (installation limited to selected repositories). New docs/ci-callback.md covers the HMAC contract end to end. It leads with the fact that the URL is signed, because that is the failure mode operators will actually meet, and http:// fails via a 307 and then a scheme mismatch - which looks nothing like a URL problem. The permissions table no longer marks half the grants "github-monitor only"; the portal needs them now. Contents moves to read/write - it reads ahk-monitor.yml and neptun.txt out of every student repository. CLAUDE.md records the non-obvious constraints a future change could quietly break: the one-status-event-per-delivery invariant, why course resolution has to precede signature validation and what must stay out of that stretch, the 12-hour ahk-monitor.yml cache, the GetForCourseAsync(Course) null trap, and that a GitHub App has one webhook URL so cutover is a flip rather than a parallel run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Five additions, each one something that cost a build or a test run: - How to probe a NuGet package's API surface here, and that the XML doc file is partial so absence from it proves nothing. Plus the two Octokit 14 facts found that way (no IncludeAllBranches; IsTemplate/Expired are non-nullable). - A curl + openssl recipe for exercising the webhook and CI callback by hand, with the dev seeder's org and secret. This is the fastest path for the next person debugging a delivery, and viaubb01 having no secret on purpose makes it a ready-made test of the failure branch. - That `git add -A` at the repo root stages .claude/settings.json, which shares permission grants with everyone who clones. Learned by doing it. - Test patterns for the m2m endpoints: build Octokit models by deserializing GitHub's JSON rather than through their constructors, which of the DI registrations WebApplicationFactory has to replace, and two MSTest-to-xUnit traps (no params in InlineData; HttpClient refuses to send a malformed Date). - That both signature comparisons must stay constant-time. The Azure Functions use string.Equals, so a future "restore parity" instinct would quietly undo a security fix - worth stating rather than leaving to a code comment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.