From 691b4854358b1e8149c347f7e5151542ab5aa678 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Mon, 4 May 2026 22:07:25 +0300 Subject: [PATCH 01/14] added a message --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c2bec0368b7..9ae7439cb49 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Run the server: go build -o notely && ./notely ``` -*This starts the server in non-database mode.* It will serve a simple webpage at `http://localhost:8080`. +_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! +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! + +Saud's version of Boot.dev's Notely app. From 29e7ca429385e404e8b3a488bb24173bd0a08d40 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 20:17:44 +0300 Subject: [PATCH 02/14] added ci file --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 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 00000000000..c3db7596c77 --- /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@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.26.0" + + - name: Force Failure + run: (exit 1) From ce07ad086815e93c8286293a684a855451a9a5a6 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 20:27:03 +0300 Subject: [PATCH 03/14] modified the ci --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3db7596c77..b79e4abf911 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,5 +18,5 @@ jobs: with: go-version: "1.26.0" - - name: Force Failure - run: (exit 1) + - name: Print Go Version + run: go version From 8e48d65818c052b45aef131c998629d2be6f61af Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 20:44:55 +0300 Subject: [PATCH 04/14] added tests and broke the code --- .github/workflows/ci.yml | 4 ++-- internal/auth/auth.go | 5 +---- internal/auth/get_api_key_test.go | 33 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 internal/auth/get_api_key_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b79e4abf911..124fbc496e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,5 +18,5 @@ jobs: with: go-version: "1.26.0" - - name: Print Go Version - run: go version + - name: Test code + run: go test ./... diff --git a/internal/auth/auth.go b/internal/auth/auth.go index f969aacf638..4ef22a6321b 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -11,10 +11,7 @@ var ErrNoAuthHeaderIncluded = errors.New("no authorization header included") // GetAPIKey - func GetAPIKey(headers http.Header) (string, error) { authHeader := headers.Get("Authorization") - if authHeader == "" { - return "", ErrNoAuthHeaderIncluded - } - 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 00000000000..1e7d8472aa0 --- /dev/null +++ b/internal/auth/get_api_key_test.go @@ -0,0 +1,33 @@ +package auth + +import ( + "net/http" + "testing" +) + +func TestGetAPIKeySuccess(t *testing.T) { + headers := http.Header{} + headers.Set("Authorization", "ApiKey my-secret-key") + + apiKey, err := GetAPIKey(headers) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if apiKey != "my-secret-key" { + t.Fatalf("expected api key %q, got %q", "my-secret-key", apiKey) + } +} + +func TestGetAPIKeyNoHeader(t *testing.T) { + headers := http.Header{} + + _, err := GetAPIKey(headers) + if err == nil { + t.Fatal("expected an error, got nil") + } + + if err != ErrNoAuthHeaderIncluded { + t.Fatalf("expected ErrNoAuthHeaderIncluded, got %v", err) + } +} From 0fc97bb7b543538b41c164142b74abc2f3fe2870 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 20:46:31 +0300 Subject: [PATCH 05/14] fixed the code --- internal/auth/auth.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 4ef22a6321b..f969aacf638 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -11,7 +11,10 @@ var ErrNoAuthHeaderIncluded = errors.New("no authorization header included") // GetAPIKey - func GetAPIKey(headers http.Header) (string, error) { authHeader := headers.Get("Authorization") - + if authHeader == "" { + return "", ErrNoAuthHeaderIncluded + } + splitAuth := strings.Split(authHeader, " ") if len(splitAuth) < 2 || splitAuth[0] != "ApiKey" { return "", errors.New("malformed authorization header") } From f5de62ead5cd3f8685e22c4178e0c552c141ae72 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 22:51:08 +0300 Subject: [PATCH 06/14] added cover to testing --- .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 124fbc496e8..20bae933b93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,4 @@ jobs: go-version: "1.26.0" - name: Test code - run: go test ./... + run: go test ./... -cover From 115a3e7bd3735544ba310fb336bbf30602285f7b Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 22:58:55 +0300 Subject: [PATCH 07/14] added badge for tests --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9ae7439cb49..7b53b05d8a2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![alt text goes here](https://github.com/saudxas/learn-cicd-starter/actions/workflows/ci.yml/badge.svg) + # learn-cicd-starter (Notely) This repo contains the starter code for the "Notely" application for the "Learn CICD" course on [Boot.dev](https://boot.dev). From 66e9f358c93a86002ea0566de357d669ca101f17 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Tue, 5 May 2026 23:30:49 +0300 Subject: [PATCH 08/14] added formating check --- .github/workflows/ci.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20bae933b93..3c01ea5b2a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,3 +20,18 @@ jobs: - name: Test code run: go test ./... -cover + style: + name: Style + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.26.0" + + - name: Check formating + run: test -z $(go fmt ./...) From 36b43a79637f321bfdfa093c9f56991592e376e1 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Wed, 6 May 2026 20:10:01 +0300 Subject: [PATCH 09/14] add code ckeck with errors --- .github/workflows/ci.yml | 6 ++++++ main.go | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c01ea5b2a4..a4310916d23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,3 +35,9 @@ jobs: - name: Check formating run: test -z $(go fmt ./...) + + - name: Install staticcheck + run: go install honnef.co/go/tools/cmd/staticcheck@latest + + - name: Run staticcheck + run: staticcheck ./... diff --git a/main.go b/main.go index 19d7366c5f7..8f575c811fb 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,11 @@ type apiConfig struct { //go:embed static/* var staticFiles embed.FS +func unused() { + // this function does nothing + // and is called nowhere +} + func main() { err := godotenv.Load(".env") if err != nil { From ba9e46b1bf65970e2be96b4e942b1dd2ee285c47 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Wed, 6 May 2026 20:13:02 +0300 Subject: [PATCH 10/14] test ci --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 8f575c811fb..56c493934dc 100644 --- a/main.go +++ b/main.go @@ -25,8 +25,8 @@ type apiConfig struct { var staticFiles embed.FS func unused() { - // this function does nothing - // and is called nowhere + // this function does nothing + // and is called nowhere } func main() { From 50f07ef05bf716f538324a9377e88b94ac040bb2 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Wed, 6 May 2026 20:15:00 +0300 Subject: [PATCH 11/14] delete the unused function --- main.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/main.go b/main.go index 56c493934dc..19d7366c5f7 100644 --- a/main.go +++ b/main.go @@ -24,11 +24,6 @@ type apiConfig struct { //go:embed static/* var staticFiles embed.FS -func unused() { - // this function does nothing - // and is called nowhere -} - func main() { err := godotenv.Load(".env") if err != nil { From bcb4dac26b9226dd5d24f9f580241724f01cd750 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Wed, 6 May 2026 20:23:10 +0300 Subject: [PATCH 12/14] add security check with failure --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4310916d23..9f9c7a7e8db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,13 @@ jobs: - name: Test code 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 From a9988b295ccba75cc18b5cb7111481942185b769 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Wed, 6 May 2026 20:36:43 +0300 Subject: [PATCH 13/14] fix changes? --- json.go | 4 +++- main.go | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/json.go b/json.go index 1e6e7985e18..6e505b38498 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 19d7366c5f7..e3af117c7b2 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,8 @@ import ( "log" "net/http" "os" + "strconv" + "time" "github.com/go-chi/chi" "github.com/go-chi/cors" @@ -34,6 +36,10 @@ func main() { if port == "" { log.Fatal("PORT environment variable is not set") } + portNum, err := strconv.Atoi(port) + if err != nil || portNum < 1 || portNum > 65535 { + log.Fatal("PORT environment variable must be a valid TCP port (1-65535)") + } apiCfg := apiConfig{} @@ -89,10 +95,11 @@ func main() { router.Mount("/v1", v1Router) srv := &http.Server{ - Addr: ":" + port, - Handler: router, + Addr: ":" + strconv.Itoa(portNum), + Handler: router, + ReadHeaderTimeout: 5 * time.Second, } - log.Printf("Serving on port: %s\n", port) + log.Printf("Serving on port: %d", portNum) log.Fatal(srv.ListenAndServe()) } From f7565f8c2405fdeb9295edd2979434925d89cde9 Mon Sep 17 00:00:00 2001 From: Saud Al-Haddad Date: Wed, 6 May 2026 20:59:25 +0300 Subject: [PATCH 14/14] add 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 00000000000..5c4e5107e7b --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,22 @@ +name: cd + +on: + push: + branches: [main] + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.26.0" + + - name: run buildprod + run: ./scripts/buildprod.sh