Skip to content
Merged
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
3 changes: 3 additions & 0 deletions ci_cd_sanity_tests/cmd/ri-exchange/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (
"github.com/LeanerCloud/CUDly/pkg/exchange"
)

// Output is the JSON-serialized result written to disk after a quote or
// exchange execution; it captures inputs, the AWS quote, and any error so the
// CI step can archive the artifact and surface a human-readable summary.
type Output struct {
Quote any `json:"quote"`
Mode string `json:"mode"`
Expand Down
8 changes: 8 additions & 0 deletions ci_cd_sanity_tests/pkg/sanity/aws/aws.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package aws implements read-only AWS sanity checks used in CI/CD to verify
// that deploy credentials have sufficient IAM permissions before a real deploy.
package aws

import (
Expand All @@ -14,6 +16,8 @@ import (
"github.com/LeanerCloud/CUDly/ci_cd_sanity_tests/pkg/sanity/report"
)

// Options controls which AWS region to target and optional safety assertions
// applied during the sanity run.
type Options struct {
Region string
ExpectedAccount string // optional safety check
Expand Down Expand Up @@ -78,6 +82,10 @@ func checkRDS(ctx context.Context, cfg aws.Config, maxList int32) (map[string]st
return map[string]string{"db_instances_seen": fmt.Sprintf("%d", len(out.DBInstances))}, nil
}

// Run executes all AWS sanity checks in sequence and returns a Report
// summarizing each result. It returns an error only for fatal setup failures
// (credential load, SDK init); individual check failures are captured inside
// the Report so callers can surface them all rather than stopping at the first.
func Run(ctx context.Context, opts Options) (*report.Report, error) {
if opts.Region == "" {
opts.Region = "us-east-1"
Expand Down
12 changes: 12 additions & 0 deletions ci_cd_sanity_tests/pkg/sanity/report/report.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package report defines the structured output types for CI/CD sanity-test runs.
package report

import (
Expand All @@ -6,6 +7,7 @@ import (
"time"
)

// Status is the outcome of a single sanity check.
type Status string

const (
Expand All @@ -14,6 +16,8 @@ const (
StatusSkip Status = "SKIP"
)

// CheckResult records the outcome of one named sanity check, including timing
// and optional key/value details for post-hoc debugging.
type CheckResult struct {
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at"`
Expand All @@ -23,6 +27,8 @@ type CheckResult struct {
Message string `json:"message,omitempty"`
}

// Report aggregates the results of a full sanity-test run against a single cloud
// provider and is serialized to JSON for upload to the CI artifact store.
type Report struct {
RunID string `json:"run_id"`
Cloud string `json:"cloud"`
Expand All @@ -32,10 +38,14 @@ type Report struct {
Results []CheckResult `json:"results"`
}

// Add appends a single check result to the report. Not safe for concurrent
// use; callers running checks in goroutines must serialize Add calls.
func (r *Report) Add(res CheckResult) {
r.Results = append(r.Results, res)
}

// HasFailures reports whether any recorded check ended in StatusFail. Skips
// and passes do not count as failures.
func (r *Report) HasFailures() bool {
for _, rr := range r.Results {
if rr.Status == StatusFail {
Expand All @@ -45,6 +55,8 @@ func (r *Report) HasFailures() bool {
return false
}

// WriteJSON serializes the report to path with indented JSON, using 0600
// permissions when creating the CI artifact file.
func (r *Report) WriteJSON(path string) error {
b, err := json.MarshalIndent(r, "", " ")
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions cmd/lambda/clear-rate-limit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ func getDomain() string {
return defaultDomain
}

// Response is the Lambda function's return value, reporting how many
// forgot_password rate-limit rows were deleted and how many rate-limit
// rows (across all endpoints) remain in the table.
type Response struct {
Message string `json:"message"`
DeletedCount int `json:"deleted_count"`
Expand Down
16 changes: 16 additions & 0 deletions internal/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,34 +237,46 @@ type LoginRequest struct {
MFACode string `json:"mfa_code,omitempty"`
}

// LoginResponse carries the JWT token and user summary returned after a successful login.
type LoginResponse struct {
Token string `json:"token"`
ExpiresAt string `json:"expires_at"`
User *UserInfo `json:"user"`
CSRFToken string `json:"csrf_token,omitempty"`
}

// UserInfo is a lightweight projection of the authenticated user included in login
// and session responses; it carries only the fields needed for client-side routing
// and display, without exposing credential hashes or internal audit fields.
type UserInfo struct {
ID string `json:"id"`
Email string `json:"email"`
Groups []string `json:"groups,omitempty"`
MFAEnabled bool `json:"mfa_enabled"`
}

// SetupAdminRequest is the one-time bootstrap payload used to create the first
// administrator account when the system has no users yet.
type SetupAdminRequest struct {
Email string `json:"email"`
Password string `json:"password"` //nolint:gosec // G117: intentional credential field in request/response struct -- value is supplied by the authenticated caller or returned once at creation; not re-stored downstream
}

// PasswordResetRequest initiates a password-reset flow by sending a reset link
// to the provided email address if it matches an existing account.
type PasswordResetRequest struct {
Email string `json:"email"`
}

// PasswordResetConfirm completes a password-reset flow by pairing the one-time
// token (delivered by email) with the user's chosen new password.
type PasswordResetConfirm struct {
Token string `json:"token"`
NewPassword string `json:"new_password"`
}

// Session holds the minimal identity claims extracted from a validated JWT and
// attached to the request context by the authentication middleware.
type Session struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Expand All @@ -276,6 +288,10 @@ type Session struct {
UserAPIKeyID string `json:"-"`
}

// User is the full user record returned by the admin user-management endpoints.
// It mirrors UserInfo's identity fields and adds CreatedAt/UpdatedAt audit
// timestamps; it is never embedded in the public-facing login or session
// responses, which use the slimmer UserInfo / CurrentUserResponse types instead.
type User struct {
ID string `json:"id"`
Email string `json:"email"`
Expand Down
Loading