From 8cb4c854d8f6bbb7172f2aef07145e13cd77556c Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 4 Dec 2024 10:38:38 -0800 Subject: [PATCH 1/9] updating gif link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cd321b..90d3e9e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ My aim is to have four commands finished for `v1.0.0`. Read more in the [Roadmap --- ## Demo -![demo](https://pokemon-objects.nyc3.digitaloceanspaces.com/demo-v0.8.0.gif) +![demo](https://poke-cli-s3-bucket.s3.us-west-2.amazonaws.com/demo.gif) --- ## Install From 3bbff1629d446d21932323f6dac17b36adf35f1b Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 4 Dec 2024 13:24:30 -0800 Subject: [PATCH 2/9] adding version flag (#78) --- cli.go | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/cli.go b/cli.go index 488447b..3cfe5b9 100644 --- a/cli.go +++ b/cli.go @@ -7,24 +7,44 @@ import ( "github.com/digitalghost-dev/poke-cli/cmd" "github.com/digitalghost-dev/poke-cli/flags" "os" + "runtime/debug" ) var ( styleBold = lipgloss.NewStyle().Bold(true) helpBorder = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#FFCC00")) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("#FFCC00")) errorColor = lipgloss.NewStyle().Foreground(lipgloss.Color("#F2055C")) errorBorder = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#F2055C")) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("#F2055C")) ) +var version = "(devel)" + +func currentVersion() { + buildInfo, ok := debug.ReadBuildInfo() + if !ok { + fmt.Println("Unable to determine version information.") + return + } + + if buildInfo.Main.Version != "" { + fmt.Printf("Version: %s\n", buildInfo.Main.Version) + } else { + fmt.Println("Version: unknown") + } +} + func runCLI(args []string) int { mainFlagSet := flag.NewFlagSet("poke-cli", flag.ContinueOnError) latestFlag := mainFlagSet.Bool("latest", false, "Prints the program's latest Docker Image and Release versions.") shortLatestFlag := mainFlagSet.Bool("l", false, "Prints the program's latest Docker Image and Release versions.") + currentVersionFlag := mainFlagSet.Bool("version", false, "Prints the current version") + shortCurrentVersionFlag := mainFlagSet.Bool("v", false, "Prints the current version") + mainFlagSet.Usage = func() { helpMessage := helpBorder.Render( "Welcome! This tool displays data related to Pokémon!", @@ -34,8 +54,8 @@ func runCLI(args []string) int { fmt.Sprintf("\n\t%-15s %s", "poke-cli [flag]", ""), "\n\n", styleBold.Render("FLAGS:"), fmt.Sprintf("\n\t%-15s %s", "-h, --help", "Shows the help menu"), - fmt.Sprintf("\n\t%-15s %s", "-l, --latest", "Prints the latest available"), - fmt.Sprintf("\n\t%-15s %s", "", "version of the program"), + fmt.Sprintf("\n\t%-15s %s", "-l, --latest", "Prints the latest version available"), + fmt.Sprintf("\n\t%-15s %s", "-v, --version", "Prints the current version"), "\n\n", styleBold.Render("AVAILABLE COMMANDS:"), fmt.Sprintf("\n\t%-15s %s", "pokemon", "Get details of a specific Pokémon"), fmt.Sprintf("\n\t%-15s %s", "types", "Get details of a specific typing"), @@ -70,6 +90,9 @@ func runCLI(args []string) int { } else if *latestFlag || *shortLatestFlag { flags.LatestFlag() return 0 + } else if *currentVersionFlag || *shortCurrentVersionFlag { + currentVersion() + return 0 } else if cmdFunc, exists := commands[os.Args[1]]; exists { cmdFunc() return 0 From e995e3b765e8518c21248098bea118faeb1b6497 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 10:32:44 -0800 Subject: [PATCH 3/9] decreasing image size with 2 build-step process --- Dockerfile | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 342cc05..8f6408f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,21 @@ -FROM golang:1.23-alpine3.19 +# build 1 +FROM golang:1.23-alpine3.19 AS build WORKDIR /app -ENV TERM=xterm-256color -ENV COLOR_OUTPUT=true +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . -COPY . /app +RUN go build -ldflags "-X main.version=v0.9.0" -o poke-cli . -RUN PATH="$PATH:~/go/bin:/usr/local/go/bin:$GOPATH/bin" +# build 2 +FROM gcr.io/distroless/static-debian12:nonroot -RUN go install +COPY --from=build /app/poke-cli /app/poke-cli + +ENV TERM=xterm-256color +ENV COLOR_OUTPUT=true -ENTRYPOINT ["poke-cli"] \ No newline at end of file +ENTRYPOINT ["/app/poke-cli"] \ No newline at end of file From 47ec2e7f2674cbff640782dce7c61b1c67bd8ea4 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 10:33:45 -0800 Subject: [PATCH 4/9] updating version flag logic (#78) --- cli.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/cli.go b/cli.go index 3cfe5b9..bfccc98 100644 --- a/cli.go +++ b/cli.go @@ -13,35 +13,45 @@ import ( var ( styleBold = lipgloss.NewStyle().Bold(true) helpBorder = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#FFCC00")) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("#FFCC00")) errorColor = lipgloss.NewStyle().Foreground(lipgloss.Color("#F2055C")) errorBorder = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#F2055C")) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("#F2055C")) ) var version = "(devel)" func currentVersion() { + if version != "(devel)" { + // Use version injected by -ldflags + fmt.Printf("Version: %s\n", version) + return + } + + // Fallback to build info when version is not set buildInfo, ok := debug.ReadBuildInfo() if !ok { - fmt.Println("Unable to determine version information.") + fmt.Println("Version: unknown (unable to read build info)") return } if buildInfo.Main.Version != "" { fmt.Printf("Version: %s\n", buildInfo.Main.Version) } else { - fmt.Println("Version: unknown") + fmt.Println("Version: (devel)") } } func runCLI(args []string) int { mainFlagSet := flag.NewFlagSet("poke-cli", flag.ContinueOnError) - latestFlag := mainFlagSet.Bool("latest", false, "Prints the program's latest Docker Image and Release versions.") - shortLatestFlag := mainFlagSet.Bool("l", false, "Prints the program's latest Docker Image and Release versions.") + // -l, --latest flag retrieves the latest Docker image and GitHub release versions available + latestFlag := mainFlagSet.Bool("latest", false, "Prints the program's latest Docker image and release versions.") + shortLatestFlag := mainFlagSet.Bool("l", false, "Prints the program's latest Docker image and release versions.") + + // -v, --version flag retrives the currently installed version currentVersionFlag := mainFlagSet.Bool("version", false, "Prints the current version") shortCurrentVersionFlag := mainFlagSet.Bool("v", false, "Prints the current version") From 93236043964e40f07c4b5556656e16b9d3607d71 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 10:35:15 -0800 Subject: [PATCH 5/9] fixing G107 (CWE-88) security issue (#80) --- connections/connection.go | 17 +++++++++++++++-- flags/version.go | 21 ++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/connections/connection.go b/connections/connection.go index df2c12f..89603d6 100644 --- a/connections/connection.go +++ b/connections/connection.go @@ -2,11 +2,13 @@ package connections import ( "encoding/json" + "errors" "flag" "fmt" "github.com/charmbracelet/lipgloss" "io" "net/http" + "net/url" "os" ) @@ -80,8 +82,19 @@ var red = lipgloss.Color("#F2055C") var errorColor = lipgloss.NewStyle().Foreground(red) // ApiCallSetup Helper function to handle API calls and JSON unmarshalling -func ApiCallSetup(url string, target interface{}) error { - res, err := http.Get(url) +func ApiCallSetup(rawURL string, target interface{}) error { + // Parse and validate the URL + parsedURL, err := url.Parse(rawURL) + if err != nil { + return fmt.Errorf("invalid URL provided: %w", err) + } + + // Check the scheme to ensure it's HTTPS + if parsedURL.Scheme != "https" { + return errors.New("only HTTPS URLs are allowed for security reasons") + } + + res, err := http.Get(parsedURL.String()) if err != nil { return fmt.Errorf("error making GET request: %w", err) } diff --git a/flags/version.go b/flags/version.go index 4d20342..890e574 100644 --- a/flags/version.go +++ b/flags/version.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "net/url" "os/exec" ) @@ -24,7 +25,25 @@ func latestRelease(githubAPIURL string) { TagName string `json:"tag_name"` } - response, err := http.Get(githubAPIURL) + // Parse and validate the URL + parsedURL, err := url.Parse(githubAPIURL) + if err != nil { + fmt.Println("Invalid URL:", err) + return + } + + // Enforce HTTPS and a specific host (e.g., api.github.com) + if parsedURL.Scheme != "https" { + fmt.Println("Only HTTPS URLs are allowed for security reasons") + return + } + if parsedURL.Host != "api.github.com" { + fmt.Println("URL host is not allowed") + return + } + + // Make the HTTP GET request + response, err := http.Get(parsedURL.String()) if err != nil { fmt.Println("Error fetching data:", err) return From ba3d62966b7b6667faeba6fc3c662915201f971e Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 10:35:55 -0800 Subject: [PATCH 6/9] adding idflags in build step --- .goreleaser.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index c8be533..46b9119 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,6 +13,8 @@ builds: - linux - windows - darwin + ldflags: + - -s -w -X main.version=v0.9.0 archives: - format: tar.gz From a9fc8be91839d48e5dd8bcb47f270a8ee6ad9b33 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 10:40:22 -0800 Subject: [PATCH 7/9] updating version numbers --- README.md | 11 +++++------ cli_test.go | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 90d3e9e..5ec9bb6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ pokemon-logo

Pokémon CLI

version-label - docker-image-size + docker-image-size ci-status-badge
@@ -68,18 +68,17 @@ _Use a Docker Image_ * Necessary. ```bash -docker run --rm -i -t digitalghostdev/poke-cli:v0.8.0 [subcommand] flag] +docker run --rm -i -t digitalghostdev/poke-cli:v0.9.0 [subcommand] flag] ``` ### Go Install -_Install the executable yourself_ +_If you have Go already, install the executable yourself_ -1. Install [Golang](https://go.dev/dl/). -2. Once installed, run the following command: +1. Run the following command: ```bash go install github.com/digitalghost-dev/poke-cli@v0 ``` -3. The tool is ready to use! +2. The tool is ready to use! --- ## Usage By running `poke-cli [-h | --help]`, it'll display information on how to use the tool. diff --git a/cli_test.go b/cli_test.go index ad5f0d5..852ad8e 100644 --- a/cli_test.go +++ b/cli_test.go @@ -110,7 +110,7 @@ func TestRunCLI(t *testing.T) { { name: "Latest Flag", args: []string{"-l"}, - expectedOutput: "Latest Docker image version: v0.7.2\nLatest release tag: v0.7.2\n", + expectedOutput: "Latest Docker image version: v0.8.0\nLatest release tag: v0.8.0\n", expectedCode: 0, }, } From c55a7aecf00ed5db9a45c7d8909da35010bb319c Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 10:40:48 -0800 Subject: [PATCH 8/9] adding ECR steps, replacing snyk with gosec --- .github/workflows/ci.yml | 69 ++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7ab943..10ac012 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ on: paths-ignore: - 'README.md' - '.github/**' + - '.dockerignore' + - '.gitignore' - 'demo**' - 'go.mod' - 'go.sum' @@ -22,11 +24,12 @@ on: branches: - main env: - VERSION_NUMBER: 'v0.8.0' - REGISTRY_NAME: digitalghostdev/poke-cli + VERSION_NUMBER: 'v0.9.0' + DOCKERHUB_REGISTRY_NAME: 'digitalghostdev/poke-cli' + AWS_REGION: 'us-west-2' jobs: - snyk: + gosec: runs-on: ubuntu-22.04 permissions: @@ -38,23 +41,20 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Run Snyk - uses: snyk/actions/golang@master - continue-on-error: true - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + - name: Run Gosec Security Scanner + uses: securego/gosec@master with: - args: --sarif-file-output=snyk.sarif --skip-unresolved=true + args: '-no-fail -fmt sarif -out results.sarif ./...' - - name: Upload Result to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v2 + - name: Upload SARIF Report + uses: github/codeql-action/upload-sarif@v3 with: - sarif_file: snyk.sarif + sarif_file: results.sarif build-docker-image: runs-on: ubuntu-22.04 - needs: [snyk] - if: needs.snyk.result == 'success' + needs: [gosec] + if: needs.gosec.result == 'success' steps: - name: Checkout @@ -81,6 +81,33 @@ jobs: name: poke-cli path: /tmp/poke-cli.tar + # Uploading to Elastic Container Registry has a backup method. + upload-to-ecr: + runs-on: ubuntu-22.04 + needs: [build-docker-image] + if: needs.build-docker-image.result == 'success' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure AWS + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Build, tag, and push image to Amazon ECR + run : | + docker build -t poke-cli:${{ env.VERSION_NUMBER }} . + docker tag poke-cli:${{ env.VERSION_NUMBER }} ${{ secrets.AWS_ECR_NAME }}:${{ env.VERSION_NUMBER }} + docker push ${{ secrets.AWS_ECR_NAME }}:${{ env.VERSION_NUMBER }} + syft: permissions: contents: 'read' @@ -150,8 +177,8 @@ jobs: architecture-build: runs-on: ubuntu-22.04 - needs: [snyk] - if: needs.snyk.result == 'success' + needs: [gosec] + if: needs.gosec.result == 'success' strategy: fail-fast: false @@ -166,7 +193,7 @@ jobs: id: meta uses: 'docker/metadata-action@v5.0.0' with: - images: ${{ env.REGISTRY_NAME }} + images: ${{ env.DOCKERHUB_REGISTRY_NAME }} - name: Set up QEMU uses: 'docker/setup-qemu-action@v3' @@ -187,7 +214,7 @@ jobs: context: . platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=${{ env.REGISTRY_NAME }},push-by-digest=true,name-canonical=true,push=true + outputs: type=image,name=${{ env.DOCKERHUB_REGISTRY_NAME }},push-by-digest=true,name-canonical=true,push=true - name: Export Digest run: | @@ -232,7 +259,7 @@ jobs: id: meta uses: 'docker/metadata-action@v5.0.0' with: - images: ${{ env.REGISTRY_NAME }} + images: ${{ env.DOCKERHUB_REGISTRY_NAME }} tags: ${{ env.VERSION_NUMBER }} - name: Login to Docker Hub @@ -245,8 +272,8 @@ jobs: working-directory: /tmp/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '${{ env.REGISTRY_NAME }}@sha256:%s ' *) + $(printf '${{ env.DOCKERHUB_REGISTRY_NAME }}@sha256:%s ' *) - name: Inspect image run: | - docker buildx imagetools inspect ${{ env.REGISTRY_NAME }}:${{ steps.meta.outputs.version }} + docker buildx imagetools inspect ${{ env.DOCKERHUB_REGISTRY_NAME }}:${{ steps.meta.outputs.version }} From 694ae439bcc95d9a80e6da661103a58d7e829fbd Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Dec 2024 16:52:54 -0800 Subject: [PATCH 9/9] adding numbers of moves to types command (#79) --- cmd/types.go | 2 +- connections/connection.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/types.go b/cmd/types.go index dd28069..4e5bf5d 100644 --- a/cmd/types.go +++ b/cmd/types.go @@ -69,7 +69,7 @@ func displayTypeDetails(typesName string, endpoint string) { selectedType := cases.Title(language.English).String(typeName) coloredType := lipgloss.NewStyle().Foreground(lipgloss.Color(getTypeColor(typeName))).Render(selectedType) - fmt.Printf("You selected the %s type.\nNumber of Pokémon with type: %d\n", coloredType, len(typesStruct.Pokemon)) + fmt.Printf("You selected the %s type.\nNumber of Pokémon with type: %d\nNumber of moves with type: %d\n", coloredType, len(typesStruct.Pokemon), len(typesStruct.Moves)) fmt.Println("----------") fmt.Println(styleBold.Render("Damage Chart:")) diff --git a/connections/connection.go b/connections/connection.go index 89603d6..003b281 100644 --- a/connections/connection.go +++ b/connections/connection.go @@ -41,8 +41,12 @@ type PokemonJSONStruct struct { } type TypesJSONStruct struct { - Name string `json:"name"` - ID int `json:"id"` + Name string `json:"name"` + ID int `json:"id"` + Moves []struct { + Name string `json:"name"` + URL string `json:"url"` + } `json:"moves"` Pokemon []struct { Pokemon struct { Name string `json:"name"`