Skip to content

Feat/env auth migration#22

Open
abbiesims wants to merge 4 commits into
mainfrom
feat/env-auth-migration
Open

Feat/env auth migration#22
abbiesims wants to merge 4 commits into
mainfrom
feat/env-auth-migration

Conversation

@abbiesims
Copy link
Copy Markdown
Contributor

Done

  • Removes credentials.json-based auth/config and use .env variables
  • Adds basic auth
  • Adds dockerfile so that we can host this on Railway (will do this next)

QA

  1. Check out this branch
  2. Migrate your credentials.json to env variables (I made a small helper script to do this):
    i. make sure you don't have a .env file already
    ii. Run python3 scripts/migrate_credentials_to_env.py --input credentials.json --output .env

To verify migration:

  1. Load env variables:
    set -a
    source .env
    set +a
  2. Run: go run cmd/bauer/main.go --doc-id "1w6nU2yt9Sec3XC_qfsGaKBIsWzkzUuHODHzRBReEctk" --dry-run (sample doc, can use a different one if you like)
  3. Check the dry run succeeds without needing --credentials flag

To verify API:

  1. In one terminal, run API_SECRET=qa-secret-123 go run cmd/app/main.go
    i. server should start on port 8090
  2. In another terminal:
  • run curl http://localhost:8090/api/v1/health - should return 200
  • run: curl -X POST http://localhost:8090/api/v1/job -H 'Content-Type: application/json' -d '{"doc_id":"x","chunk_size":1,"page_refresh":false}'
    • should return unauthorized (no auth passed in)
  • run: curl -X POST http://localhost:8090/api/v1/job -u "bauer:qa-secret-123" -H 'Content-Type: application/json' -d '{"doc_id":"x","chunk_size":1,"page_refresh":false}'
    • should return 202
    • to check wrong password, run curl -X POST http://localhost:8090/api/v1/job -u "bauer:wrong-secret" -H 'Content-Type: application/json' -d '{"doc_id":"x","chunk_size":1,"page_refresh":false}'
      • should return unauthorized

To verify dockerfile

  • Run docker build -t bauer-api-test .
  • Image should build

Copy link
Copy Markdown
Contributor

@omarelkashef omarelkashef left a comment

Choose a reason for hiding this comment

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

Thank you for the PR. Code looks good. Only a couple of nitpicks. For QA, the port is not exposed unless I run docker with -p 8090:8090 and I needed to inject the .env file.

const apiUser = "bauer"

func APIBasicAuth(next http.Handler, secret string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it be easier to add middlewares to handlers that need it than using an if statement?

username, password, ok := r.BasicAuth()
if !ok || !secureEquals(username, apiUser) || !secureEquals(password, secret) {
w.Header().Set("WWW-Authenticate", `Basic realm="bauer-api"`)
http.Error(w, "unauthorized", http.StatusUnauthorized)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just for the same of consistency, we can use types.UnAuthorized function.

Comment thread README.md
@@ -30,10 +30,16 @@ N.B. You need to install [Copilot CLI](https://docs.github.com/en/copilot/how-to
## Configuration
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you add docker instruction to the README?

Comment thread cmd/app/v1/api.go


func GetHealth(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unrelated to your PR, but can you move these two lines? Success().Render() already sets the header

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates Google service-account authentication/config from a checked-in credentials.json approach to GOOGLE_* environment variables (optionally loaded from .env files), and adds basic auth + containerization to support hosting the API (e.g., on Railway).

Changes:

  • Replace credentials-file auth with env-based credential loading and provide a migration script + .env.example.
  • Add .env loading behavior to CLI/API config and update validation/tests/docs accordingly.
  • Add API HTTP basic auth middleware and a multi-stage Dockerfile for building/running bauer-api.

Reviewed changes

Copilot reviewed 22 out of 24 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
scripts/migrate_credentials_to_env.py Adds helper to convert service-account JSON keys into .env variables.
internal/orchestrator/orchestrator.go Updates GDocs client initialization to no longer require a credentials path.
internal/gdocs/service.go Switches client auth to use credentials loaded from environment variables.
internal/gdocs/credentials.go Implements env-based credential loading, validation, and JSON marshaling for Google SDK auth.
internal/config/env.go Adds .env.local / .env loading via godotenv.
internal/config/config_test.go Updates config validation tests to use GOOGLE_* env vars instead of temp credentials files.
internal/config/config.go Removes CredentialsPath and validates required GOOGLE_* env vars; centralizes defaults.
internal/config/cli.go Removes --credentials flag; loads env files before validation.
go.mod Adds godotenv dependency.
go.sum Adds checksum entries for godotenv.
docs/ARCHITECTURE.md Updates architecture docs to reflect env-based config requirements.
credentials.json Removes the template credentials JSON file from the repo.
cmd/bauer/main.go Updates credential-related error guidance to reference GOOGLE_* variables instead of a file path.
cmd/app/v1/api.go Removes credentials path usage in job config and tweaks request/response error handling.
cmd/app/types/config.go Removes credentials-path config, loads env files, and introduces API_SECRET validation.
cmd/app/main.go Adds basic auth middleware and minor cleanup around orchestrator naming and Getwd error handling.
cmd/app/core/middleware/basic_auth.go Introduces HTTP basic auth middleware (excluding /api/v1/health).
Taskfile.yml Updates local run task to drop the --credentials flag.
README.md Updates setup instructions to use .env + migration helper; documents API basic auth usage.
Dockerfile Adds a multi-stage build for producing a minimal bauer-api runtime image.
.gitignore Ignores .env* (except .env.example) and credentials.json.
.env.example Provides a template for required GOOGLE_* vars and API_SECRET.
.env Removes previously committed .env contents.
.dockerignore Prevents secrets and local artifacts from being copied into Docker build context.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread go.mod
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

github.com/joho/godotenv is imported directly (e.g. internal/config/env.go), so it shouldn't be marked // indirect. Running go mod tidy (or removing the indirect marker) will keep go.mod accurate and avoid churn in future dependency updates.

Suggested change
github.com/joho/godotenv v1.5.1 // indirect
github.com/joho/godotenv v1.5.1

Copilot uses AI. Check for mistakes.
Comment thread cmd/app/v1/api.go
slog.Error("error writing response", "error", renderErr.Error(), "requestID", requestID)
}
return nil, err
return nil, renderErr
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

In getJobFromRequest, on JSON decode failure you return renderErr (the error from writing the HTTP response) instead of the decode error. If rendering succeeds renderErr will be nil, causing the handler to continue with a nil payload and likely panic or misbehave. Return the original decode error (or a wrapped version) regardless of whether rendering succeeded, and log/ignore the render error separately.

Suggested change
return nil, renderErr
return nil, fmt.Errorf("invalid request body: %w", err)

Copilot uses AI. Check for mistakes.
Comment thread internal/gdocs/service.go

credentialsJSON, err := credentials.JSON()
if err != nil {
return nil, err
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

credentials.JSON() errors are returned without context (return nil, err). Wrapping this with a descriptive message (similar to the other error returns in this function) will make troubleshooting misconfigured env credentials easier.

Suggested change
return nil, err
return nil, fmt.Errorf("failed to get credentials JSON: %w", err)

Copilot uses AI. Check for mistakes.
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.

3 participants