diff --git a/.github/workflows/deploy-cloudrun.yaml b/.github/workflows/deploy-cloudrun.yaml index 9b990a2..ba6a88a 100644 --- a/.github/workflows/deploy-cloudrun.yaml +++ b/.github/workflows/deploy-cloudrun.yaml @@ -48,10 +48,16 @@ name: Build and Deploy to Cloud Run with KRM + on: + pull_request: + branches: + - main + workflow_dispatch: push: branches: - - jarrpa/dev/cloudy + - main + - jarrpa/2026-pittsburgh env: PROJECT_ID: oceanic-gecko-338300 @@ -76,12 +82,13 @@ jobs: - name: Google Auth id: auth - uses: 'google-github-actions/auth@v0' + uses: 'google-github-actions/auth@v3' with: token_format: 'access_token' workload_identity_provider: '${{ vars.WIF_PROVIDER }}' # e.g. - projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider service_account: '${{ vars.WIF_SERVICE_ACCOUNT }}' # e.g. - my-service-account@my-project.iam.gserviceaccount.com + # NOTE: Alternative option - authentication via credentials json # - name: Google Auth # id: auth diff --git a/.github/workflows/deploy-cloudrun/cloud-run-service.template.yaml b/.github/workflows/deploy-cloudrun/cloud-run-service.template.yaml new file mode 100644 index 0000000..5fef08d --- /dev/null +++ b/.github/workflows/deploy-cloudrun/cloud-run-service.template.yaml @@ -0,0 +1,47 @@ +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: ${SERVICE} +spec: + template: + spec: + containerConcurrency: 80 + timeoutSeconds: 60 + serviceAccountName: ${SERVICE_ACCOUNT} + containers: + - name: backend-service + image: ${IMAGE} + args: + - test + ports: + - name: http1 + containerPort: 8080 + resources: + limits: + cpu: 1000m + memory: 1Gi + volumeMounts: + - name: run + mountPath: /app/run + - name: conf + mountPath: /app/conf + startupProbe: + timeoutSeconds: 240 + periodSeconds: 240 + failureThreshold: 3 + tcpSocket: + port: 8080 + volumes: + - name: run + csi: + driver: gcsfuse.run.googleapis.com + volumeAttributes: + bucketName: ${RUN_BUCKET_NAME} + - name: conf + csi: + driver: gcsfuse.run.googleapis.com + volumeAttributes: + bucketName: ${CONF_BUCKET_NAME} + traffic: + - percent: 100 + latestRevision: true diff --git a/internal/cert_manager.go b/internal/cert_manager.go index d8a6f30..0342d3b 100644 --- a/internal/cert_manager.go +++ b/internal/cert_manager.go @@ -54,6 +54,7 @@ func VerifyCertificate(certificate string) (string, bool) { scanErr := result.Scan(&certificateRole) if scanErr != nil { + LogError(scanErr, "error verifying certificate") return "none", false } diff --git a/internal/scheduler.go b/internal/scheduler.go index 09ced8d..a84c1ad 100644 --- a/internal/scheduler.go +++ b/internal/scheduler.go @@ -130,7 +130,7 @@ func userInSchedule(database *sql.DB, uuid string) bool { // Wipes the json file func WipeSchedule() { - schedPath := filepath.Join(CachedConfigs.RuntimeDirectory, "json") + schedPath := filepath.Join(CachedConfigs.RuntimeDirectory, "schedule.json") file, openErr := OpenWithPermissions(schedPath) if openErr != nil { diff --git a/internal/server.go b/internal/server.go index 18d783d..99c948c 100644 --- a/internal/server.go +++ b/internal/server.go @@ -369,7 +369,7 @@ func handleLoginRequest(writer http.ResponseWriter, request *http.Request) { Path: "/", HttpOnly: true, Secure: secureCookies, - SameSite: http.SameSiteStrictMode, + SameSite: http.SameSiteNoneMode, }) http.SetCookie(writer, &http.Cookie{ Name: "certificate", @@ -377,7 +377,7 @@ func handleLoginRequest(writer http.ResponseWriter, request *http.Request) { Path: "/", HttpOnly: true, Secure: secureCookies, - SameSite: http.SameSiteStrictMode, + SameSite: http.SameSiteNoneMode, }) if role == "super" { @@ -404,7 +404,7 @@ func handleLogoutRequest(writer http.ResponseWriter, request *http.Request) { MaxAge: -1, HttpOnly: true, Secure: secureCookies, - SameSite: http.SameSiteStrictMode, + SameSite: http.SameSiteNoneMode, }) // clear certificate cookie @@ -415,7 +415,7 @@ func handleLogoutRequest(writer http.ResponseWriter, request *http.Request) { MaxAge: -1, HttpOnly: true, Secure: secureCookies, - SameSite: http.SameSiteStrictMode, + SameSite: http.SameSiteNoneMode, }) httpResponsef(writer, "Problem writing http response to logout request", "Logged out") @@ -546,9 +546,13 @@ func handleScoreChange(writer http.ResponseWriter, request *http.Request) { // The okCode parameter exists because some requests require a 200 response even before acting. This is honestly just trial and error to determine. func handleWithCORS(handler http.HandlerFunc, okCode bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", CachedConfigs.FrontendDomain) + allowOrigin := CachedConfigs.FrontendDomain + if r.Header.Get("Origin") != "" { + allowOrigin = r.Header.Get("Origin") + } + w.Header().Set("Access-Control-Allow-Origin", allowOrigin) w.Header().Set("Access-Control-Allow-Methods", "*") - w.Header().Set("Access-Control-Allow-Headers", "Content-Type, username, uuid, displayName, Filename, userInput, color, type") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, username, uuid, displayName, Filename, userInput, color, type") w.Header().Set("Access-Control-Expose-Headers", "Role") w.Header().Set("Access-Control-Allow-Credentials", "true") @@ -838,10 +842,14 @@ func getAuthFromCookies(request *http.Request) RequestAuth { if c, err := request.Cookie("uuid"); err == nil && c != nil { auth.UUID = c.Value + } else if err != nil { + LogError(err, "error getting request cookie 'uuid'") } if c, err := request.Cookie("certificate"); err == nil && c != nil { auth.Certificate = c.Value + } else if err != nil { + LogError(err, "error getting request cookie 'certificate'") } role, ok := VerifyCertificate(auth.Certificate) diff --git a/internal/setup.go b/internal/setup.go index 77f6724..f7856e4 100644 --- a/internal/setup.go +++ b/internal/setup.go @@ -748,10 +748,10 @@ func configCustomEvent(configs GeneralConfigs) CustomEventConfigs { } if configs.CustomEventConfigs.CustomSchedule { - LogMessagef("Using %s/json as the match schedule! Please make that it meets your non-TBA event schedule manually.", CachedConfigs.RuntimeDirectory) + LogMessagef("Using %s/schedule.json as the match schedule! Please make that it meets your non-TBA event schedule manually.", CachedConfigs.RuntimeDirectory) } else { WipeSchedule() - LogMessage("Not using a ") + LogMessage("Not using a schedule") } configs.CustomEventConfigs.Configured = true diff --git a/internal/sheet_writer.go b/internal/sheet_writer.go index 4569828..5641a42 100644 --- a/internal/sheet_writer.go +++ b/internal/sheet_writer.go @@ -92,19 +92,18 @@ var Srv *sheets.Service func SetupSheetsAPI(creds []byte) { ctx := context.Background() - config, err := google.ConfigFromJSON(creds, "https://www.googleapis.com/auth/spreadsheets") + client, err := google.DefaultClient(context.Background(), sheets.SpreadsheetsScope) if err != nil { FatalError(err, "Unable to parse client secret file to config: %v") } - client := getClient(config) - Srv, err = sheets.NewService(ctx, option.WithHTTPClient(client)) if err != nil { FatalError(err, "Unable to retrieve Sheets client: %v") } - LogMessagef("Client retrieved for: %v", Srv.UserAgent) + LogMessagef("Client retrieved for: %v", Srv.BasePath) SpreadsheetId = CachedConfigs.SpreadSheetID + LogMessagef("Using SpreadsheetId: %v", CachedConfigs.SpreadSheetID) } // Writes team data from multi-scouting to a specified line @@ -256,6 +255,9 @@ func IsSheetValid(id string) bool { spreadsheetId := id readRange := "RawData!A1:1" _, err := Srv.Spreadsheets.Values.Get(spreadsheetId, readRange).Do() + if err != nil { + LogErrorf(err, "Failed to read from %q on sheet %q", readRange, spreadsheetId) + } return err == nil } diff --git a/internal/user_db.go b/internal/user_db.go index 948ed20..cb30579 100644 --- a/internal/user_db.go +++ b/internal/user_db.go @@ -69,7 +69,7 @@ func GetUUID(username string, createIfNot bool) (string, bool) { } if !userExists { - NewUser(username, "") //Empty UUID for assignment later + NewUser(username, uuid.New().String()) //Empty UUID for assignment later } var userId string