From 4200217959c686389dc3180b85b43552bbdfad58 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 14:57:24 +0800 Subject: [PATCH 01/22] chapter1 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c2bec0368b..14b85187c1 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,5 @@ go build -o notely && ./notely *This starts the server in non-database mode.* It will serve a simple webpage at `http://localhost:8080`. You do *not* need to set up a database or any interactivity on the webpage yet. Instructions for that will come later in the course! + +SHAUN version of Boot.dev's Notely app \ No newline at end of file From 1bdf9d373f0f58e36b9f6d7c88c99cb2c9ae362e Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 16:35:18 +0800 Subject: [PATCH 02/22] chapter 1 2nd commit --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ .gitignore | 1 + 2 files changed, 23 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..664032071d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: ci + +on: + pull_request: + branches: [main] + +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: "1.26.0" + + - name: Force Failure + run: (exit 1) \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2092f54e78..c5cd3b1472 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ out .env learn-cicd-starter notely +.DS_Store From 0f7e633cc23dd7827982b5cc81fd362061f6eed2 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 16:41:50 +0800 Subject: [PATCH 03/22] go version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 664032071d..a37446d7a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,4 @@ jobs: go-version: "1.26.0" - name: Force Failure - run: (exit 1) \ No newline at end of file + run: go version \ No newline at end of file From 8250821abbe0ef72f35ada446840ae967d68df98 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 17:03:04 +0800 Subject: [PATCH 04/22] temporary break --- .github/workflows/ci.yml | 2 +- internal/auth/auth.go | 2 +- internal/auth/get_api_key_test.go | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 internal/auth/get_api_key_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a37446d7a3..26587862b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,4 @@ jobs: go-version: "1.26.0" - name: Force Failure - run: go version \ No newline at end of file + run: go test ./... \ No newline at end of file diff --git a/internal/auth/auth.go b/internal/auth/auth.go index f969aacf63..ce13a9560f 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -14,7 +14,7 @@ func GetAPIKey(headers http.Header) (string, error) { if authHeader == "" { return "", ErrNoAuthHeaderIncluded } - splitAuth := strings.Split(authHeader, " ") + splitAuth := strings.Split(authHeader, ",") if len(splitAuth) < 2 || splitAuth[0] != "ApiKey" { return "", errors.New("malformed authorization header") } diff --git a/internal/auth/get_api_key_test.go b/internal/auth/get_api_key_test.go new file mode 100644 index 0000000000..05b95c1c2b --- /dev/null +++ b/internal/auth/get_api_key_test.go @@ -0,0 +1,20 @@ +package auth + +import ( + "testing" + "net/http" +) + +func TestGetAPIKey(t *testing.T) { + headers := http.Header{} + headers.Set("Authorization", "ApiKey abc123") + + got, err := GetAPIKey(headers) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := "abc123" + if want != got { + t.Fatalf("expected: %v, got: %v", want, got) + } +} \ No newline at end of file From 0d434c122e94c6b470656b42f318eedd9c67d209 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 17:04:16 +0800 Subject: [PATCH 05/22] temporary break - fix --- internal/auth/auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/auth/auth.go b/internal/auth/auth.go index ce13a9560f..f969aacf63 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -14,7 +14,7 @@ func GetAPIKey(headers http.Header) (string, error) { if authHeader == "" { return "", ErrNoAuthHeaderIncluded } - splitAuth := strings.Split(authHeader, ",") + splitAuth := strings.Split(authHeader, " ") if len(splitAuth) < 2 || splitAuth[0] != "ApiKey" { return "", errors.New("malformed authorization header") } From ffe067dba62b61972f8e4b81ff5041ac3873029b Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 17:07:09 +0800 Subject: [PATCH 06/22] cover --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26587862b4..05c9aa9d8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,4 @@ jobs: go-version: "1.26.0" - name: Force Failure - run: go test ./... \ No newline at end of file + run: go test ./... -cover \ No newline at end of file From 87bc675d0bd24d03b7362dd4dc316b2e304f527f Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 17:10:54 +0800 Subject: [PATCH 07/22] cicd badge --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14b85187c1..92a0923db2 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This repo contains the starter code for the "Notely" application for the "Learn CICD" course on [Boot.dev](https://boot.dev). +![alt text goes here](https://github.com/shaunfg/learn-cicd-starter/actions/workflows/ci.yml/badge.svg) + ## Local Development Make sure you're on Go version 1.22+. @@ -22,4 +24,5 @@ go build -o notely && ./notely You do *not* need to set up a database or any interactivity on the webpage yet. Instructions for that will come later in the course! -SHAUN version of Boot.dev's Notely app \ No newline at end of file +SHAUN version of Boot.dev's Notely app + From b40b535697e29aa9e05894cce0e6ef9f6a41babc Mon Sep 17 00:00:00 2001 From: shaunfg Date: Mon, 10 Aug 2026 17:25:14 +0800 Subject: [PATCH 08/22] style formatting --- .github/workflows/ci.yml | 18 +++++++++++++++++- internal/auth/get_api_key_test.go | 4 ++-- main.go | 5 +++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05c9aa9d8a..b674810b54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,20 @@ jobs: go-version: "1.26.0" - name: Force Failure - run: go test ./... -cover \ No newline at end of file + run: go test ./... -cover + + style: + name: Style + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: "1.26.0" + + - name: formatting + run: test -z $(go fmt ./...) \ No newline at end of file diff --git a/internal/auth/get_api_key_test.go b/internal/auth/get_api_key_test.go index 05b95c1c2b..b8ccf37c33 100644 --- a/internal/auth/get_api_key_test.go +++ b/internal/auth/get_api_key_test.go @@ -1,8 +1,8 @@ package auth import ( - "testing" "net/http" + "testing" ) func TestGetAPIKey(t *testing.T) { @@ -17,4 +17,4 @@ func TestGetAPIKey(t *testing.T) { if want != got { t.Fatalf("expected: %v, got: %v", want, got) } -} \ No newline at end of file +} diff --git a/main.go b/main.go index 19d7366c5f..bb58787a0d 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ type apiConfig struct { var staticFiles embed.FS func main() { + err := godotenv.Load(".env") if err != nil { log.Printf("warning: assuming default configuration. .env unreadable: %v", err) @@ -38,6 +39,7 @@ func main() { apiCfg := apiConfig{} // https://github.com/libsql/libsql-client-go/#open-a-connection-to-sqld + // libsql://[your-database].turso.io?authToken=[your-auth-token] dbURL := os.Getenv("DATABASE_URL") if dbURL == "" { @@ -90,8 +92,7 @@ func main() { router.Mount("/v1", v1Router) srv := &http.Server{ Addr: ":" + port, - Handler: router, - } + Handler: router} log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) From 9dbc5f8330a8457aeec8f6c0443599decd4b37d5 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 11:49:08 +0800 Subject: [PATCH 09/22] unused --- .github/workflows/ci.yml | 8 +++++++- main.go | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b674810b54..e07f64195e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,4 +35,10 @@ jobs: go-version: "1.26.0" - name: formatting - run: test -z $(go fmt ./...) \ No newline at end of file + run: test -z $(go fmt ./...) + + - name: Install staticcheck + run: go install honnef.co/go/tools/cmd/staticcheck@latest + + - name: linting + run: staticcheck ./... \ No newline at end of file diff --git a/main.go b/main.go index bb58787a0d..f6b4b5f942 100644 --- a/main.go +++ b/main.go @@ -97,3 +97,9 @@ func main() { log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) } + + +func unused() { + // this function does nothing + // and is called nowhere +} \ No newline at end of file From 7e1a97b104712d04a3bc2b61b7fc23f6352eb248 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 11:50:50 +0800 Subject: [PATCH 10/22] unused --- main.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/main.go b/main.go index f6b4b5f942..89e324cdd4 100644 --- a/main.go +++ b/main.go @@ -96,10 +96,4 @@ func main() { log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) -} - - -func unused() { - // this function does nothing - // and is called nowhere } \ No newline at end of file From a27dd4b13b21749ec2904fbafe578e96c2716b32 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 11:52:06 +0800 Subject: [PATCH 11/22] unused --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 89e324cdd4..bb58787a0d 100644 --- a/main.go +++ b/main.go @@ -96,4 +96,4 @@ func main() { log.Printf("Serving on port: %s\n", port) log.Fatal(srv.ListenAndServe()) -} \ No newline at end of file +} From 3987573b29772f82f7f119ee0a312a10b7842c4e Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 11:58:14 +0800 Subject: [PATCH 12/22] gosec --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e07f64195e..5ac6634a11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,4 +41,10 @@ jobs: run: go install honnef.co/go/tools/cmd/staticcheck@latest - name: linting - run: staticcheck ./... \ No newline at end of file + run: staticcheck ./... + + - name: Install gosec + run: go install github.com/securego/gosec/v2/cmd/gosec@latest + + - name: sec checks + run: gosec ./... \ No newline at end of file From 8c5d27d73480a4c98c440083bbb77fb3a995bc18 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:10:39 +0800 Subject: [PATCH 13/22] fix security errors --- json.go | 4 +++- main.go | 14 +++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/json.go b/json.go index 1e6e7985e1..7fd6ae29ec 100644 --- a/json.go +++ b/json.go @@ -30,5 +30,7 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { return } w.WriteHeader(code) - w.Write(dat) + if _, err := w.Write(dat); err != nil { + log.Printf("error writing response: %v", err) + } } diff --git a/main.go b/main.go index bb58787a0d..b659e9072c 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,9 @@ import ( "log" "net/http" "os" + "time" + "strconv" + "strings" "github.com/go-chi/chi" "github.com/go-chi/cors" @@ -91,9 +94,14 @@ func main() { router.Mount("/v1", v1Router) srv := &http.Server{ - Addr: ":" + port, - Handler: router} + Addr: ":" + port, + Handler: router, + ReadHeaderTimeout: 5 * time.Second} - log.Printf("Serving on port: %s\n", port) + if _, err := strconv.Atoi(port); err != nil { + log.Fatal("invalid port: value must be numeric") + } + + log.Printf("Serving on port: %s\n", strings.ReplaceAll(port, "\n", "")) log.Fatal(srv.ListenAndServe()) } From ab91621e1bae30a5f5bbdb49849bd55c336f3c81 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:11:31 +0800 Subject: [PATCH 14/22] fix security errors --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index b659e9072c..e7a2a7bb28 100644 --- a/main.go +++ b/main.go @@ -7,9 +7,9 @@ import ( "log" "net/http" "os" - "time" "strconv" "strings" + "time" "github.com/go-chi/chi" "github.com/go-chi/cors" From 30044968c9d1d8a4ef5727676ca0a80b3acc2ca3 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:14:01 +0800 Subject: [PATCH 15/22] fix security errors --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ac6634a11..c5391ccee7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,5 +46,5 @@ jobs: - name: Install gosec run: go install github.com/securego/gosec/v2/cmd/gosec@latest - - name: sec checks + - name: gosec run: gosec ./... \ No newline at end of file From 973ab3f5d26d1b0ce682d17a41d0b62ea147aea4 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:17:36 +0800 Subject: [PATCH 16/22] fix security errors --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5391ccee7..5d36dd5386 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,9 +42,14 @@ jobs: - name: linting run: staticcheck ./... + + gosec: + name: Go Security + runs-on: ubuntu-latest + steps: - name: Install gosec run: go install github.com/securego/gosec/v2/cmd/gosec@latest - - name: gosec + - name: gosec run run: gosec ./... \ No newline at end of file From cf4f7cc5324d990746d25519473144e79211b073 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:20:01 +0800 Subject: [PATCH 17/22] fix security errors --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d36dd5386..f0e1e567da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,14 @@ jobs: runs-on: ubuntu-latest steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: "1.26.0" + - name: Install gosec run: go install github.com/securego/gosec/v2/cmd/gosec@latest From 7a1de52bae5d891606f8f26831d957bc5539ca40 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:22:28 +0800 Subject: [PATCH 18/22] fix security errors --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0e1e567da..3a568b9a94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: run: staticcheck ./... gosec: - name: Go Security + name: gosec runs-on: ubuntu-latest steps: From 776b4dd866b4f1beea7a616195e29a2a026d84a4 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:25:14 +0800 Subject: [PATCH 19/22] fix security errors --- .github/workflows/ci.yml | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a568b9a94..b8edf51cdc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,11 +16,17 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.26.0" + go-version: "1.25.1" - - name: Force Failure + - name: Run unit tests run: go test ./... -cover - + + - name: Install gosec + run: go install github.com/securego/gosec/v2/cmd/gosec@latest + + - name: Run gosec + run: gosec ./... + style: name: Style runs-on: ubuntu-latest @@ -32,32 +38,13 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.26.0" - - - name: formatting + go-version: "1.25.1" + + - name: Check formatting run: test -z $(go fmt ./...) - name: Install staticcheck run: go install honnef.co/go/tools/cmd/staticcheck@latest - - name: linting + - name: Run staticcheck run: staticcheck ./... - - gosec: - name: gosec - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version: "1.26.0" - - - name: Install gosec - run: go install github.com/securego/gosec/v2/cmd/gosec@latest - - - name: gosec run - run: gosec ./... \ No newline at end of file From f0436a4204c3a8dd35521196df973cd8f6bb0c90 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:26:48 +0800 Subject: [PATCH 20/22] fix security errors --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8edf51cdc..027341e521 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.25.1" + go-version: "1.25.8" - name: Run unit tests run: go test ./... -cover From 35faea4d2479849ae7ca405e187ab9fe63a71f30 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Tue, 11 Aug 2026 12:35:59 +0800 Subject: [PATCH 21/22] CD --- .github/workflows/cd.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/cd.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000000..7472b2e4b5 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,22 @@ +name: cd + +on: + push: + branches: [main] + +jobs: + tests: + name: Deploy + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: "1.25.8" + + - name: Build Code + run: ./scripts/buildprod.sh \ No newline at end of file From c205b211704e6135b107353a4d90bbaecf3095c4 Mon Sep 17 00:00:00 2001 From: shaunfg Date: Wed, 12 Aug 2026 12:09:35 +0800 Subject: [PATCH 22/22] GCP CD --- .github/workflows/cd.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 7472b2e4b5..ba3ae0bd61 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -19,4 +19,20 @@ jobs: go-version: "1.25.8" - name: Build Code - run: ./scripts/buildprod.sh \ No newline at end of file + run: ./scripts/buildprod.sh + + gcloud: + steps: + - id: 'auth' + uses: 'google-github-actions/auth@v2' + with: + credentials_json: '${{ secrets.GCP_CREDENTIALS }}' + + - name: 'Set up Cloud SDK' + uses: 'google-github-actions/setup-gcloud@v3' + + - name: 'Use gcloud CLI' + run: 'gcloud info' + + - name: build docker image + run: gcloud builds submit --tag us-central1-docker.pkg.dev/project-8619a5e0-9ad6-4e4a-936/notely-ar-repo/notely:latest .