Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e693e2cdd | ||
|
|
9440c651b6 | ||
|
|
ccb44fa253 | ||
|
|
cee0378f8f |
@@ -130,10 +130,8 @@ jobs:
|
||||
--target runner \
|
||||
--build-arg VERSION="$VERSION" \
|
||||
-t "git.garvis.dev/dmg/minecraft-account-manager:${VERSION}" \
|
||||
-t git.garvis.dev/dmg/minecraft-account-manager:latest \
|
||||
.
|
||||
docker push "git.garvis.dev/dmg/minecraft-account-manager:${VERSION}"
|
||||
docker push git.garvis.dev/dmg/minecraft-account-manager:latest
|
||||
|
||||
- name: Build and push Discord bot image
|
||||
if: steps.release.outputs.created == 'true'
|
||||
@@ -145,10 +143,8 @@ jobs:
|
||||
--target bot \
|
||||
--build-arg VERSION="$VERSION" \
|
||||
-t "git.garvis.dev/dmg/minecraft-account-manager-bot:${VERSION}" \
|
||||
-t git.garvis.dev/dmg/minecraft-account-manager-bot:latest \
|
||||
.
|
||||
docker push "git.garvis.dev/dmg/minecraft-account-manager-bot:${VERSION}"
|
||||
docker push git.garvis.dev/dmg/minecraft-account-manager-bot:latest
|
||||
|
||||
- name: Build and push migration image
|
||||
if: steps.release.outputs.created == 'true'
|
||||
@@ -160,10 +156,8 @@ jobs:
|
||||
--target migrate \
|
||||
--build-arg VERSION="$VERSION" \
|
||||
-t "git.garvis.dev/dmg/minecraft-account-manager-migrate:${VERSION}" \
|
||||
-t git.garvis.dev/dmg/minecraft-account-manager-migrate:latest \
|
||||
.
|
||||
docker push "git.garvis.dev/dmg/minecraft-account-manager-migrate:${VERSION}"
|
||||
docker push git.garvis.dev/dmg/minecraft-account-manager-migrate:latest
|
||||
|
||||
- name: Create Gitea release and upload Velocity JAR
|
||||
if: steps.release.outputs.created == 'true'
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createAuthRepository, ipObservations, recordEvent } from "@minecraft-ac
|
||||
import { getClientIp } from "@minecraft-account-manager/network";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { applicationUrl } from "@/lib/application-url";
|
||||
import { db } from "@/lib/database";
|
||||
import { getIpIntelligence, toAuditIpData } from "@/lib/ip-intelligence";
|
||||
|
||||
@@ -38,7 +39,7 @@ export async function GET(request: NextRequest) {
|
||||
]);
|
||||
|
||||
const destination = result.user.firstName ? "/account" : "/welcome";
|
||||
const response = NextResponse.redirect(new URL(destination, request.url));
|
||||
const response = NextResponse.redirect(applicationUrl(destination));
|
||||
response.cookies.set(SESSION_COOKIE_NAME, result.sessionToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
@@ -49,7 +50,7 @@ export async function GET(request: NextRequest) {
|
||||
return response;
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidLoginCodeError) {
|
||||
return NextResponse.redirect(new URL("/auth/error", request.url));
|
||||
return NextResponse.redirect(applicationUrl("/auth/error"));
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applicationUrl } from "./application-url";
|
||||
|
||||
describe("applicationUrl", () => {
|
||||
it("builds browser redirects from the configured public application URL", () => {
|
||||
expect(applicationUrl("/welcome", "https://portal.somc.club"))
|
||||
.toEqual(new URL("https://portal.somc.club/welcome"));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
export function applicationUrl(path: string, baseUrl = process.env.APP_URL) {
|
||||
if (!baseUrl) throw new Error("APP_URL is required to build public application URLs");
|
||||
return new URL(path, baseUrl);
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## 2026-08-01
|
||||
|
||||
* **Fix**: Build magic-link redirects from the configured public portal URL instead of the reverse proxy's internal request origin.
|
||||
* **Verify**: Confirmed `v1.1.1` left all pre-existing `latest` digests unchanged while publishing versioned artifacts.
|
||||
* **Refine**: Removed mutable `latest` publication so all deployable artifacts use explicit semantic versions.
|
||||
* **Verify**: Confirmed the `v1.1.0` Discord bot image and matching web, migration, and Velocity artifacts.
|
||||
* **Extend**: Added a releasable Discord bot image and a dependency-free web health endpoint for Kubernetes deployment.
|
||||
* **Verify**: Confirmed the initial `v1.0.0` release, public Velocity JAR, and versioned and `latest` web and migration image manifests.
|
||||
* **Create**: Added Gitea CI and semantic-release pipelines for downloadable Velocity JARs and versioned web and migration images.
|
||||
|
||||
@@ -3,7 +3,7 @@ type: User Story
|
||||
title: Authenticate with a Discord magic link
|
||||
description: Discord users receive private single-use links that establish secure portal sessions.
|
||||
tags: [player, discord, authentication, security]
|
||||
timestamp: 2026-08-01T18:43:58Z
|
||||
timestamp: 2026-08-01T20:43:46Z
|
||||
story_id: US-002
|
||||
status: verified
|
||||
---
|
||||
@@ -19,6 +19,7 @@ As a Discord community member, I want `/register` and `/account` to issue a priv
|
||||
- [x] Given a login token, then it expires after ten minutes and can be consumed only once.
|
||||
- [x] Given repeated link requests, then requests are rate limited per Discord user and older active links are invalidated.
|
||||
- [x] Given a valid link, when it is consumed, then the Discord user is created or refreshed and a secure seven-day session is established.
|
||||
- [x] Given a magic-link result behind a reverse proxy, then the browser is redirected through the configured public application URL rather than an internal container address.
|
||||
- [x] Given an invalid, expired, or consumed link, then the user sees a safe recovery page instructing them to request another link.
|
||||
|
||||
# Implementation
|
||||
@@ -27,10 +28,12 @@ As a Discord community member, I want `/register` and `/account` to issue a priv
|
||||
- [`packages/auth/src/index.ts`](../packages/auth/src/index.ts)
|
||||
- [`packages/database/src/auth-repository.ts`](../packages/database/src/auth-repository.ts)
|
||||
- [`apps/web/src/app/auth/discord/route.ts`](../apps/web/src/app/auth/discord/route.ts)
|
||||
- [`apps/web/src/lib/application-url.ts`](../apps/web/src/lib/application-url.ts)
|
||||
|
||||
# Validation
|
||||
|
||||
- [`packages/auth/test/magic-link.test.ts`](../packages/auth/test/magic-link.test.ts)
|
||||
- [`apps/web/src/lib/application-url.test.ts`](../apps/web/src/lib/application-url.test.ts)
|
||||
- Discord command and authentication workspaces pass TypeScript validation.
|
||||
|
||||
# Related Stories
|
||||
|
||||
@@ -3,9 +3,9 @@ type: User Story
|
||||
title: Build and publish versioned releases
|
||||
description: Gitea Actions validate every change and publish semantically versioned Velocity and container artifacts.
|
||||
tags: [operations, ci, release, velocity, docker]
|
||||
timestamp: 2026-08-01T19:46:09Z
|
||||
timestamp: 2026-08-01T20:05:49Z
|
||||
story_id: US-016
|
||||
status: implemented
|
||||
status: verified
|
||||
---
|
||||
|
||||
# User Story
|
||||
@@ -20,9 +20,10 @@ As a platform operator, I want automated validation and semantic releases, so th
|
||||
- [x] Main-branch conventional commits determine the next semantic version and create a `vMAJOR.MINOR.PATCH` tag.
|
||||
- [x] A release build embeds the semantic version in the Velocity plugin and JAR filename.
|
||||
- [x] A public Gitea release exposes the versioned Velocity JAR as a downloadable asset.
|
||||
- [x] Releases publish versioned and `latest` web runtime images to the Gitea registry.
|
||||
- [ ] Releases publish versioned and `latest` Discord bot images to the Gitea registry.
|
||||
- [x] Releases publish versioned and `latest` migration images that run versioned Drizzle migrations.
|
||||
- [x] Releases publish semantically versioned web runtime images to the Gitea registry.
|
||||
- [x] Releases publish semantically versioned Discord bot images to the Gitea registry.
|
||||
- [x] Releases publish semantically versioned migration images that run versioned Drizzle migrations.
|
||||
- [x] Releases do not publish mutable container tags such as `latest`.
|
||||
- [x] Runtime containers use unprivileged users and exclude development source and secrets where practical.
|
||||
- [x] Operators are told which repository secrets must be configured before the first push.
|
||||
|
||||
@@ -37,7 +38,7 @@ As a platform operator, I want automated validation and semantic releases, so th
|
||||
|
||||
# Validation
|
||||
|
||||
Local OKF, lint, typecheck, test, Next.js build, and versioned Velocity JAR checks pass. Initial Gitea CI and release runs succeeded. Release `v1.0.0` provides a publicly downloadable JAR whose Velocity metadata reports `1.0.0`. Registry manifests were resolved for versioned and `latest` web and migration images. Discord bot image publication is implemented for the next feature release. Pull-request commitlint configuration is present; its conditional execution will be exercised by the first pull request.
|
||||
Local OKF, lint, typecheck, test, Next.js build, and versioned Velocity JAR checks pass. Initial Gitea CI and release runs succeeded. Release `v1.0.0` provides a publicly downloadable JAR whose Velocity metadata reports `1.0.0`. Registry manifests were resolved for the published semantic-version tags. Release `v1.1.0` also publishes resolvable versioned web, Discord bot, and migration manifests and a public Velocity JAR whose metadata reports `1.1.0`. Release `v1.1.1` published immutable semantic-version tags only; prior `latest` digests remained unchanged. Pull-request commitlint configuration is present; its conditional execution will be exercised by the first pull request.
|
||||
|
||||
# Related Stories
|
||||
|
||||
|
||||
+1
-4
@@ -32,13 +32,10 @@ Each release creates:
|
||||
|
||||
- Gitea release asset `minecraft-account-manager-velocity-VERSION.jar`
|
||||
- `git.garvis.dev/dmg/minecraft-account-manager:VERSION`
|
||||
- `git.garvis.dev/dmg/minecraft-account-manager:latest`
|
||||
- `git.garvis.dev/dmg/minecraft-account-manager-bot:VERSION`
|
||||
- `git.garvis.dev/dmg/minecraft-account-manager-bot:latest`
|
||||
- `git.garvis.dev/dmg/minecraft-account-manager-migrate:VERSION`
|
||||
- `git.garvis.dev/dmg/minecraft-account-manager-migrate:latest`
|
||||
|
||||
Use immutable version tags for deployments. `latest` is a convenience pointer to the newest release.
|
||||
Only immutable semantic-version tags are published. Mutable tags such as `latest` must never be used in deployments or release-asset URLs.
|
||||
|
||||
## Discord bot
|
||||
|
||||
|
||||
Reference in New Issue
Block a user