Skip to content

feat: add test-login endpoint and integration testing skills#198

Open
ptone wants to merge 1 commit into
mainfrom
scion/integration-test-workflow
Open

feat: add test-login endpoint and integration testing skills#198
ptone wants to merge 1 commit into
mainfrom
scion/integration-test-workflow

Conversation

@ptone

@ptone ptone commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #197

  • Add POST /api/v1/auth/test-login endpoint gated behind --enable-test-login flag for browser/Playwright integration testing
  • New integration-testing skill in contrib-repo documenting 4 auth scenarios (hubclient, CLI, curl, Playwright/browser)
  • Updated qa-tester template and scion-process lifecycle to reference the new skill

Changes

Go (Track 1)

  • pkg/hub/handlers_test_login.go — new handler: accepts email/role/displayName, provisions user, generates JWT, sets session cookie
  • pkg/hub/web.goEnableTestLogin config field, route registration
  • pkg/hub/auth.go — add test-login to unauthenticated endpoints list
  • cmd/server.go--enable-test-login flag
  • cmd/server_foreground.go — wire flag to WebServerConfig
  • pkg/hub/handlers_test_login_test.go — 8 test cases covering success, defaults, validation, gating, existing users

Contrib-repo (Track 2)

  • skills/integration-testing/SKILL.md — new skill with 4 auth scenario docs
  • templates/qa-tester/agents.md — reference integration-testing skill, add auth step to workflow
  • skills/scion-process/SKILL.md — integration testing lifecycle guidance

Test plan

  • All 8 new tests pass (go test ./pkg/hub/ -run TestHandleTestLogin)
  • Build succeeds (go build ./cmd/scion/)
  • Pre-existing test suite unaffected (failures are pre-existing, unrelated)
  • Deploy to integration instance with --enable-test-login and validate browser session flow

Add POST /api/v1/auth/test-login gated behind --enable-test-login flag.
The endpoint provisions a test user, generates JWTs, and sets a session
cookie — enabling Playwright and browser-based integration tests without
requiring OAuth. Separate from --dev-auth to keep workstation mode clean.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new /api/v1/auth/test-login endpoint to facilitate integration testing by bypassing OAuth and provisioning test users. It includes command-line flag integration, route registration, and comprehensive unit tests. The review feedback highlights two main areas of improvement: limiting the request body size on the unauthenticated endpoint to prevent potential Denial of Service (DoS) attacks, and addressing issues in the user update logic, specifically handling display name updates correctly and avoiding silent failures by checking the error returned from UpdateUser.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +60 to +64
var req TestLoginRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

To prevent potential Denial of Service (DoS) attacks via large request payloads on this unauthenticated endpoint, it is recommended to limit the request body size using http.MaxBytesReader.

Suggested change
var req TestLoginRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}
var req TestLoginRequest
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 4096)).Decode(&req); err != nil {
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}

Comment on lines +80 to +110
if req.DisplayName == "" {
req.DisplayName = req.Email
}

ctx := r.Context()

// Find or create user
user, err := ws.store.GetUserByEmail(ctx, req.Email)
if err != nil {
user = &store.User{
ID: generateID(),
Email: req.Email,
DisplayName: req.DisplayName,
Role: req.Role,
Status: "active",
Created: time.Now(),
LastLogin: time.Now(),
}
if err := ws.store.CreateUser(ctx, user); err != nil {
slog.Error("test-login: failed to create user", "email", req.Email, "error", err)
http.Error(w, "failed to create user", http.StatusInternalServerError)
return
}
} else {
user.LastLogin = time.Now()
user.Role = req.Role
if req.DisplayName != user.Email {
user.DisplayName = req.DisplayName
}
_ = ws.store.UpdateUser(ctx, user)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

There are two issues in this block:

  1. If an existing user has a custom display name and the client explicitly requests to update it to their email address, the update is ignored because of the req.DisplayName != user.Email check.
  2. The error returned by ws.store.UpdateUser is ignored using the blank identifier _, which can lead to silent failures.

We can resolve both issues by keeping req.DisplayName empty if not provided, defaulting it only during new user creation, and properly logging any errors from UpdateUser.

	ctx := r.Context()

	// Find or create user
	user, err := ws.store.GetUserByEmail(ctx, req.Email)
	if err != nil {
		displayName := req.DisplayName
		if displayName == "" {
			displayName = req.Email
		}
		user = &store.User{
			ID:          generateID(),
			Email:       req.Email,
			DisplayName: displayName,
			Role:        req.Role,
			Status:      "active",
			Created:     time.Now(),
			LastLogin:   time.Now(),
		}
		if err := ws.store.CreateUser(ctx, user); err != nil {
			slog.Error("test-login: failed to create user", "email", req.Email, "error", err)
			http.Error(w, "failed to create user", http.StatusInternalServerError)
			return
		}
	} else {
		user.LastLogin = time.Now()
		user.Role = req.Role
		if req.DisplayName != "" && req.DisplayName != user.DisplayName {
			user.DisplayName = req.DisplayName
		}
		if err := ws.store.UpdateUser(ctx, user); err != nil {
			slog.Warn("test-login: failed to update user on login", "email", req.Email, "error", err)
		}
	}

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.

feat: integration testing workflow — test-login endpoint and skills

1 participant