diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml deleted file mode 100644 index 270a358d4..000000000 --- a/.github/workflows/build_docker.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Build Docker image and publish to ECR - -on: - workflow_dispatch: - inputs: - image_tag: - description: "ECR image tag type" - required: false - type: choice - options: - - "latest" - - "release" - default: "latest" - push: - branches: - - main - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build-and-push-image: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - - - name: Get package version - id: package-version - run: echo "version=$(node -p 'require("./package.json").version')" >> $GITHUB_OUTPUT - - - name: Get image tag - id: get-image-tag - env: - IS_RELEASE: ${{ github.event_name == 'workflow_dispatch' && inputs.image_tag == 'release' }} - VERSION: ${{ steps.package-version.outputs.version }} - run: | - if [ "$IS_RELEASE" = "true" ]; then - echo "image_tag=$VERSION" >> $GITHUB_OUTPUT - else - echo "image_tag=latest-SNAPSHOT" >> $GITHUB_OUTPUT - fi - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_ECR }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_ECR }} - aws-region: us-east-1 - role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME_ECR }} - role-duration-seconds: 3600 - role-session-name: ExplorerImageUpdate - - - name: Login to Amazon ECR - id: login-ecr-public - uses: aws-actions/amazon-ecr-login@376925c9d111252e87ae59691e5a442dd100ef6a # v2.1.3 - with: - registry-type: public - - - name: Build, tag, and push Docker image - env: - REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} - REGISTRY_ALIAS: neptune - REPOSITORY: graph-explorer - IMAGE_TAG: ${{ steps.get-image-tag.outputs.image_tag }} - run: | - docker build -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG . - docker build --build-arg NEPTUNE_NOTEBOOK=true -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-$IMAGE_TAG . - docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG - docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-$IMAGE_TAG - - - name: Update latest tag for release - if: ${{ github.event_name == 'workflow_dispatch' && inputs.image_tag == - 'release' }} - env: - REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} - REGISTRY_ALIAS: neptune - REPOSITORY: graph-explorer - IMAGE_TAG: ${{ steps.get-image-tag.outputs.image_tag }} - run: | - docker tag $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:latest - docker tag $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-$IMAGE_TAG $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-latest - docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:latest - docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-latest diff --git a/.github/workflows/unit.yml b/.github/workflows/ci.yml similarity index 56% rename from .github/workflows/unit.yml rename to .github/workflows/ci.yml index 24465aa6e..4b2840a12 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Unit Tests +name: CI on: workflow_dispatch: @@ -27,7 +27,7 @@ jobs: - name: Review dependencies for vulnerabilities uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 - install-and-test: + checks: runs-on: ubuntu-latest steps: - name: Checkout repository @@ -40,12 +40,38 @@ jobs: uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version-file: "package.json" + cache: "pnpm" - - name: Install package and dependencies + - name: Install dependencies run: pnpm install --frozen-lockfile - name: Run type, lint, and format checks run: pnpm checks - - name: Run package tests with code coverage + tests: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + + - name: Set up pnpm + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 + + - name: Set up Node.js + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version-file: "package.json" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run tests with code coverage run: pnpm coverage + + - name: Upload coverage report + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: coverage-report + path: coverage/ + retention-days: 14 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 000000000..674ea4d84 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,179 @@ +name: Docker + +on: + workflow_dispatch: + inputs: + image_tag: + description: "ECR image tag type" + required: false + type: choice + options: + - "latest" + - "release" + default: "latest" + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + + - name: Build Docker image + run: | + docker build -t graph-explorer . + docker build -t graph-explorer-sagemaker --build-arg NEPTUNE_NOTEBOOK=true . + + - name: Scan Docker image for vulnerabilities + uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 + with: + image-ref: graph-explorer + severity: HIGH,CRITICAL + exit-code: 1 + + - name: Ensure openSSL is installed + run: | + docker run --rm --entrypoint="" graph-explorer openssl version + docker run --rm --entrypoint="" graph-explorer-sagemaker openssl version + + - name: Verify unnecessary packages are removed + run: | + docker run --rm --entrypoint="" graph-explorer sh -c ' + (command -v npm && echo "FAIL: npm found" && exit 1) || echo "npm removed" + (command -v pnpm && echo "FAIL: pnpm found" && exit 1) || echo "pnpm removed" + (command -v corepack && echo "FAIL: corepack found" && exit 1) || echo "corepack removed" + (command -v python3 && echo "FAIL: python3 found" && exit 1) || echo "python3 removed" + (command -v yum && echo "FAIL: yum found" && exit 1) || echo "yum removed" + (command -v dnf && echo "FAIL: dnf found" && exit 1) || echo "dnf removed" + ' + docker run --rm --entrypoint="" graph-explorer-sagemaker sh -c ' + (command -v npm && echo "FAIL: npm found" && exit 1) || echo "npm removed" + (command -v pnpm && echo "FAIL: pnpm found" && exit 1) || echo "pnpm removed" + (command -v corepack && echo "FAIL: corepack found" && exit 1) || echo "corepack removed" + (command -v python3 && echo "FAIL: python3 found" && exit 1) || echo "python3 removed" + (command -v yum && echo "FAIL: yum found" && exit 1) || echo "yum removed" + (command -v dnf && echo "FAIL: dnf found" && exit 1) || echo "dnf removed" + ' + + - name: Verify standard server starts and responds + run: | + docker run -d --name test-server \ + -p 8080:80 \ + -e PROXY_SERVER_HTTPS_CONNECTION=false \ + graph-explorer + trap 'docker rm -f test-server 2>/dev/null' EXIT + + for i in $(seq 1 30); do + if curl -sf http://localhost:8080/status; then + echo "" + echo "Server responded on /status" + break + fi + if [ "$i" -eq 30 ]; then + echo "FAIL: Server did not respond within 30 seconds" + docker logs test-server + exit 1 + fi + sleep 1 + done + + - name: Verify sagemaker server starts and responds + run: | + docker run -d --name test-server-sagemaker \ + -p 9250:9250 \ + graph-explorer-sagemaker + trap 'docker rm -f test-server-sagemaker 2>/dev/null' EXIT + + for i in $(seq 1 30); do + if curl -sf http://localhost:9250/status; then + echo "" + echo "Sagemaker server responded on /status" + break + fi + if [ "$i" -eq 30 ]; then + echo "FAIL: Sagemaker server did not respond within 30 seconds" + docker logs test-server-sagemaker + exit 1 + fi + sleep 1 + done + + push-to-ecr: + if: github.ref == 'refs/heads/main' + needs: build-and-test + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + + - name: Get package version + id: package-version + run: echo "version=$(node -p 'require("./package.json").version')" >> $GITHUB_OUTPUT + + - name: Get image tag + id: get-image-tag + env: + IS_RELEASE: ${{ github.event_name == 'workflow_dispatch' && inputs.image_tag == 'release' }} + VERSION: ${{ steps.package-version.outputs.version }} + run: | + if [ "$IS_RELEASE" = "true" ]; then + echo "image_tag=$VERSION" >> $GITHUB_OUTPUT + else + echo "image_tag=latest-SNAPSHOT" >> $GITHUB_OUTPUT + fi + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_ECR }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_ECR }} + aws-region: us-east-1 + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME_ECR }} + role-duration-seconds: 3600 + role-session-name: ExplorerImageUpdate + + - name: Login to Amazon ECR + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@376925c9d111252e87ae59691e5a442dd100ef6a # v2.1.3 + with: + registry-type: public + + - name: Build, tag, and push Docker image + env: + REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} + REGISTRY_ALIAS: neptune + REPOSITORY: graph-explorer + IMAGE_TAG: ${{ steps.get-image-tag.outputs.image_tag }} + run: | + docker build -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG . + docker build --build-arg NEPTUNE_NOTEBOOK=true -t $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-$IMAGE_TAG . + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-$IMAGE_TAG + + - name: Update latest tag for release + if: github.event_name == 'workflow_dispatch' && inputs.image_tag == 'release' + env: + REGISTRY: ${{ steps.login-ecr-public.outputs.registry }} + REGISTRY_ALIAS: neptune + REPOSITORY: graph-explorer + IMAGE_TAG: ${{ steps.get-image-tag.outputs.image_tag }} + run: | + docker tag $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:$IMAGE_TAG $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:latest + docker tag $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-$IMAGE_TAG $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-latest + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:latest + docker push $REGISTRY/$REGISTRY_ALIAS/$REPOSITORY:sagemaker-latest diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 439c1ec6a..e4de473d3 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -46,16 +46,35 @@ jobs: - name: Checkout repository uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - - name: Scan Docker image for vulnerabilities + - name: Build Docker images + run: | + docker build -t graph-explorer . + docker build -t graph-explorer-sagemaker --build-arg NEPTUNE_NOTEBOOK=true . + + - name: Scan standard image for vulnerabilities uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: - image-ref: public.ecr.aws/neptune/graph-explorer:latest-SNAPSHOT - vuln-type: os + image-ref: graph-explorer + vuln-type: os,library format: sarif output: trivy-image-results.sarif - - name: Upload Trivy image results to GitHub Security tab + - name: Upload standard image results to GitHub Security tab uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: sarif_file: trivy-image-results.sarif category: docker-image-scan + + - name: Scan sagemaker image for vulnerabilities + uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 + with: + image-ref: graph-explorer-sagemaker + vuln-type: os,library + format: sarif + output: trivy-sagemaker-results.sarif + + - name: Upload sagemaker image results to GitHub Security tab + uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + with: + sarif_file: trivy-sagemaker-results.sarif + category: docker-sagemaker-image-scan diff --git a/.github/workflows/test_build_docker.yml b/.github/workflows/test_build_docker.yml deleted file mode 100644 index a41d37674..000000000 --- a/.github/workflows/test_build_docker.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Test build the Docker image - -on: - workflow_dispatch: - pull_request: - branches: - - main - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - test-build-docker-image: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - - - name: Build Docker image - run: | - docker build -t test-image . - docker build -t test-image-neptune --build-arg NEPTUNE_NOTEBOOK=true . - - - name: Scan Docker image for vulnerabilities - uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 - with: - image-ref: test-image - severity: HIGH,CRITICAL - exit-code: 1 - - - name: Ensure openSSL is installed - run: | - docker run --rm --entrypoint="" test-image openssl --version - docker run --rm --entrypoint="" test-image-neptune openssl --version - - - name: Verify unnecessary packages are removed - run: | - docker run --rm --entrypoint="" test-image sh -c ' - (command -v npm && echo "FAIL: npm found" && exit 1) || echo "✓ npm removed" - (command -v pnpm && echo "FAIL: pnpm found" && exit 1) || echo "✓ pnpm removed" - (command -v corepack && echo "FAIL: corepack found" && exit 1) || echo "✓ corepack removed" - (command -v python3 && echo "FAIL: python3 found" && exit 1) || echo "✓ python3 removed" - (command -v yum && echo "FAIL: yum found" && exit 1) || echo "✓ yum removed" - (command -v dnf && echo "FAIL: dnf found" && exit 1) || echo "✓ dnf removed" - ' - docker run --rm --entrypoint="" test-image-neptune sh -c ' - (command -v npm && echo "FAIL: npm found" && exit 1) || echo "✓ npm removed" - (command -v pnpm && echo "FAIL: pnpm found" && exit 1) || echo "✓ pnpm removed" - (command -v corepack && echo "FAIL: corepack found" && exit 1) || echo "✓ corepack removed" - (command -v python3 && echo "FAIL: python3 found" && exit 1) || echo "✓ python3 removed" - (command -v yum && echo "FAIL: yum found" && exit 1) || echo "✓ yum removed" - (command -v dnf && echo "FAIL: dnf found" && exit 1) || echo "✓ dnf removed" - ' - - - name: Verify server starts and responds - run: | - docker run -d --name test-server \ - -p 8080:80 \ - -e PROXY_SERVER_HTTPS_CONNECTION=false \ - test-image - trap 'docker rm -f test-server 2>/dev/null' EXIT - - # Wait for the server to be ready - for i in $(seq 1 30); do - if curl -sf http://localhost:8080/status; then - echo "" - echo "✓ Server responded on /status" - break - fi - if [ "$i" -eq 30 ]; then - echo "FAIL: Server did not respond within 30 seconds" - docker logs test-server - exit 1 - fi - sleep 1 - done