Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ you through it.
## Setup

```bash
git clone https://github.com/<org>/<repo>.git
cd <repo>/web
git clone https://github.com/ScalerOpenSourceLabsOrg/scaleropensourcelabs.com.git
cd scaleropensourcelabs.com/web
npm install
npm run dev # http://localhost:3000
# port 3000 is often taken; use `npm run dev -- -p 3001`
Expand Down
6 changes: 4 additions & 2 deletions web/components/JoinGate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,10 @@ function Gate() {
<p className="text-display-md font-semibold">Sign-in is not set up here.</p>
<p className="measure mt-4 text-body text-haze">
This deployment has no Firebase configuration, so registration is switched off.
If you are running the site locally, see <code>web/.env.example</code>. If you
are seeing this on the live site, that is a bug — please tell us.
When sign-in is available, only students with an <strong className="text-ink">@{DOMAIN}</strong>
address can register. If you are running the site locally, see{" "}
<code>web/.env.example</code>. If you are seeing this on the live site, that is a
bug — please tell us.
</p>
<a href={`mailto:${LINKS.email}`} className="btn btn-secondary mt-6">
Email the organisers
Expand Down
42 changes: 23 additions & 19 deletions web/scripts/smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -205,34 +205,38 @@ await pg.waitForTimeout(700);
// deleted. The page held an anonymous application form for a spell; membership is an
// @sst.scaler.com address, which is the one thing that form could not check, so the door
// and the test are the same act now.
const joinState = await pg.evaluate(() => {
const text = document.querySelector("main")?.innerText ?? "";
return {
configured: /continue with google|sign in with your college account/i.test(text),
unconfigured: /sign-in is not set up here/i.test(text),
hasFormFields:
document.querySelectorAll("main input, main select, main textarea").length > 0,
statesDomain: /sst\.scaler\.com/i.test(text),
};
});

// CI intentionally runs without Firebase configuration. In that environment /join must
// show the honest "not configured" state instead of a fake sign-in control. In a configured
// deployment it must show the real college-account sign-in gate. Both states must remain
// form-free.
ok(
"join offers sign-in, not a form",
(await pg.evaluate(() =>
/continue with google/i.test(document.querySelector("main")?.innerText ?? ""),
)),
"join shows a valid gate state",
joinState.configured || joinState.unconfigured,
);
// THE ASSERTION THAT WOULD CATCH A REGRESSION HERE. A form reappearing on this page is
// the specific thing this change removed, so its absence is checked rather than assumed —
// zero inputs of any kind in the main column.
ok(
"and no application fields survive on the page",
(await pg.evaluate(
() => document.querySelectorAll("main input, main select, main textarea").length,
)) === 0,
!joinState.hasFormFields,
);
ok(
"join keeps ?path in the URL",
new URL(pg.url()).searchParams.get("path") === "program-track",
);
// THE DOMAIN RULE IS ON THE PAGE, not just in the rules. It is the whole membership test
// and the one sentence a reader cannot afford to skim past, so a copy pass that removed it
// would leave people signing in with a personal Gmail and being refused with no warning.
ok(
"and states the one address that can register",
(await pg.evaluate(() =>
/sst\.scaler\.com/i.test(document.querySelector("main")?.innerText ?? ""),
)),
);
// The domain rule is important in both states: a configured gate explains the membership
// requirement, while the unconfigured state explains what will be required once auth is
// available.
ok("and states the one address that can register", joinState.statesDomain);

// The form must NOT be reachable without signing in. This is a UI assertion, not a
// security one — the boundary is firestore.rules — but a form rendering to a signed-out
// visitor would mean the gate had broken open.
Expand Down