diff --git a/.github/workflows/cluster-pipeline.yaml b/.github/workflows/cluster-pipeline.yaml new file mode 100644 index 0000000..ad798d4 --- /dev/null +++ b/.github/workflows/cluster-pipeline.yaml @@ -0,0 +1,436 @@ +name: Cluster Pipeline + +on: + push: + paths: + - 'cluster-api/**' + - 'cluster-service/**' + - 'cluster-status/**' + - 'cluster-ui/**' + branches: + - '**' + pull_request: + paths: + - 'cluster-api/**' + - 'cluster-service/**' + - 'cluster-status/**' + - 'cluster-ui/**' + workflow_dispatch: + + +jobs: + changed_files: + runs-on: ubuntu-latest + outputs: + python_api: ${{ steps.changes.outputs.cluster-api }} + python_service: ${{ steps.changes.outputs.cluster-service }} + go: ${{ steps.changes.outputs.cluster-status }} + typescript: ${{ steps.changes.outputs.cluster-ui }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get changed files by directory + id: changes + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + BASE_SHA=${{ github.event.pull_request.base.sha }} + HEAD_SHA=${{ github.event.pull_request.head.sha }} + else + BASE_SHA=$(git rev-parse HEAD^) + HEAD_SHA=$(git rev-parse HEAD) + fi + + echo "Checking changes between $BASE_SHA and $HEAD_SHA" + + # Check each directory separately + if git diff --name-only $BASE_SHA $HEAD_SHA | grep -q "^cluster-api/"; then + echo "cluster-api=true" >> $GITHUB_OUTPUT + else + echo "cluster-api=false" >> $GITHUB_OUTPUT + fi + + if git diff --name-only $BASE_SHA $HEAD_SHA | grep -q "^cluster-service/"; then + echo "cluster-service=true" >> $GITHUB_OUTPUT + else + echo "cluster-service=false" >> $GITHUB_OUTPUT + fi + + if git diff --name-only $BASE_SHA $HEAD_SHA | grep -q "^cluster-status/"; then + echo "cluster-status=true" >> $GITHUB_OUTPUT + else + echo "cluster-status=false" >> $GITHUB_OUTPUT + fi + + if git diff --name-only $BASE_SHA $HEAD_SHA | grep -q "^cluster-ui/"; then + echo "cluster-ui=true" >> $GITHUB_OUTPUT + else + echo "cluster-ui=false" >> $GITHUB_OUTPUT + fi + + cluster-api-lint: + needs: changed_files + if: needs.changed_files.outputs.python_api == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check for Python files + id: check-python + run: | + if find cluster-api -name "*.py" -print -quit | grep -q .; then + echo "has_python_files=true" >> $GITHUB_OUTPUT + else + echo "has_python_files=false" >> $GITHUB_OUTPUT + fi + + - name: Set up Python + if: steps.check-python.outputs.has_python_files == 'true' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install Python linting tools + if: steps.check-python.outputs.has_python_files == 'true' + working-directory: cluster-api + run: | + python -m pip install --upgrade pip + pip install flake8 black isort pylint + + - name: Run Pylint + if: steps.check-python.outputs.has_python_files == 'true' + working-directory: cluster-api + run: | + find . -type f -name "*.py" -not -path "*/\.*" -exec pylint {} + || echo "Linting completed with warnings" + gitleaks-cluster-api: + name: GitLeaks Security Scan + runs-on: ubuntu-latest + needs: cluster-api-lint + permissions: + security-events: write + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run GitLeaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + config-path: .gitleaks.toml + enable-upload-artifact: true + report-format: sarif + report-path: gitleaks-report.sarif + + cluster-api-build: + runs-on: ubuntu-latest + needs: gitleaks-cluster-api + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + steps: + - uses: actions/checkout@v4 + - name: Docker Build and Push + if: github.event_name != 'pull_request' + working-directory: cluster-api + env: + CLUSTER_API_REGISTRY_URL: ${{secrets.CLUSTER_API_REGISTRY_URL}} + CLUSTER_API_REGISTRY_USER: ${{secrets.CLUSTER_API_REGISTRY_USER}} + CLUSTER_API_REGISTRY_PASSWORD: ${{secrets.CLUSTER_API_REGISTRY_PASSWORD}} + + run: | + echo "Docker login to $REGISTRY_HOST" + + + docker login -u ${{secrets.CLUSTER_API_REGISTRY_USER}} -p "${{secrets.CLUSTER_API_REGISTRY_PASSWORD}}" + + echo "Building Docker image" + docker build . -t ${{secrets.CLUSTER_API_REGISTRY_URL}}:${{ github.sha }} -t ${{secrets.CLUSTER_API_REGISTRY_URL}}:latest + + echo "Pushing Docker image" + docker push ${{secrets.CLUSTER_API_REGISTRY_URL}}:${{ github.sha }} + docker push ${{secrets.CLUSTER_API_REGISTRY_URL}}:latest + + echo "Clean up" + if [ -f .id_rsa ]; then rm .id_rsa; fi + + cluster-service-lint: + needs: changed_files + if: needs.changed_files.outputs.python_service == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check for Python files + id: check-python + run: | + if find cluster-service -name "*.py" -print -quit | grep -q .; then + echo "has_python_files=true" >> $GITHUB_OUTPUT + else + echo "has_python_files=false" >> $GITHUB_OUTPUT + fi + + - name: Set up Python + if: steps.check-python.outputs.has_python_files == 'true' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install Python linting tools + if: steps.check-python.outputs.has_python_files == 'true' + working-directory: cluster-service + run: | + python -m pip install --upgrade pip + pip install flake8 black isort pylint + + - name: Run Pylint + if: steps.check-python.outputs.has_python_files == 'true' + working-directory: cluster-service + run: | + + gitleaks-cluster-service: + name: GitLeaks Security Scan + runs-on: ubuntu-latest + needs: cluster-service-lint + permissions: + security-events: write + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run GitLeaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + config-path: .gitleaks.toml + enable-upload-artifact: true + report-format: sarif + report-path: gitleaks-report.sarif + + cluster-service-build: + runs-on: ubuntu-latest + needs: gitleaks-cluster-service + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + steps: + - uses: actions/checkout@v4 + - name: Docker Build and Push + if: github.event_name != 'pull_request' + working-directory: cluster-api + env: + CLUSTER_SERIVCE_REGISTRY_URL: ${{secrets.CLUSTER_SERVICE_REGISTRY_URL}} + CLUSTER_SERIVCE_REGISTRY_USER: ${{secrets.CLUSTER_SERVICE_REGISTRY_USER}} + CLUSTER_SERIVCE_REGISTRY_PASSWORD: ${{secrets.CLUSTER_SERVICE_REGISTRY_PASSWORD}} + + run: | + echo "Docker login to $REGISTRY_HOST" + + + docker login -u ${{secrets.CLUSTER_SERVICE_REGISTRY_USER}} -p "${{secrets.CLUSTER_SERVICE_REGISTRY_PASSWORD}}" + + echo "Building Docker image" + docker build . -t ${{secrets.CLUSTER_SERVICE_REGISTRY_URL}}:${{ github.sha }} -t ${{secrets.CLUSTER_SERVICE_REGISTRY_URL}}:latest + + echo "Pushing Docker image" + docker push ${{secrets.CLUSTER_SERVICE_REGISTRY_URL}}:${{ github.sha }} + docker push ${{secrets.CLUSTER_SERVICE_REGISTRY_URL}}:latest + + echo "Clean up" + if [ -f .id_rsa ]; then rm .id_rsa; fi + + cluster-status-lint: + needs: changed_files + if: needs.changed_files.outputs.go == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + cache: true + + - name: Install Go tools + run: | + go install golang.org/x/tools/cmd/goimports@latest + go install honnef.co/go/tools/cmd/staticcheck@latest + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + echo "$HOME/go/bin" >> $GITHUB_PATH + + - name: Go Format Check + working-directory: cluster-status + run: | + if [ -n "$(gofmt -l .)" ]; then + echo "The following files need formatting:" + gofmt -l . + echo "Please run 'gofmt -w .' to format your code." + exit 1 + fi + + - name: Go Imports Check + working-directory: cluster-status + run: | + if [ -n "$(goimports -l .)" ]; then + echo "The following files have incorrect imports:" + goimports -l . + echo "Please run 'goimports -w .' to fix imports." + exit 1 + fi + + - name: Run golangci-lint + working-directory: cluster-status + run: golangci-lint run --timeout=5m + + - name: Run staticcheck + working-directory: cluster-status + run: staticcheck ./... + + gitleaks-cluster-status: + name: GitLeaks Security Scan + runs-on: ubuntu-latest + needs: cluster-status-lint + permissions: + security-events: write + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run GitLeaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + config-path: .gitleaks.toml + enable-upload-artifact: true + report-format: sarif + report-path: gitleaks-report.sarif + + cluster-status-build: + runs-on: ubuntu-latest + needs: gitleaks-cluster-status + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + steps: + - uses: actions/checkout@v4 + - name: Docker Build and Push + if: github.event_name != 'pull_request' + working-directory: cluster-api + env: + CLUSTER_STATUS_REGISTRY_URL: ${{secrets.CLUSTER_STATUS_REGISTRY_URL}} + CLUSTER_STATUS_REGISTRY_USER: ${{secrets.CLUSTER_STATUS_REGISTRY_USER}} + CLUSTER_STATUS_REGISTRY_PASSWORD: ${{secrets.CLUSTER_STATUS_REGISTRY_PASSWORD}} + + run: | + echo "Docker login to $REGISTRY_HOST" + + + docker login -u ${{secrets.CLUSTER_STATUS_REGISTRY_USER}} -p "${{secrets.CLUSTER_STATUS_REGISTRY_PASSWORD}}" + + echo "Building Docker image" + docker build . -t ${{secrets.CLUSTER_STATUS_REGISTRY_URL}}:${{ github.sha }} -t ${{secrets.CLUSTER_STATUS_REGISTRY_URL}}:latest + + echo "Pushing Docker image" + docker push ${{secrets.CLUSTER_STATUS_REGISTRY_URL}}:${{ github.sha }} + docker push ${{secrets.CLUSTER_STATUS_REGISTRY_URL}}:latest + + echo "Clean up" + if [ -f .id_rsa ]; then rm .id_rsa; fi + + cluster-ui-lint: + needs: changed_files + if: needs.changed_files.outputs.typescript == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: cluster-ui/package-lock.json + + - name: Install Node.js dependencies + working-directory: cluster-ui + run: | + npm install -g eslint@^8.56.0 typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin + npm ci + + - name: Lint TypeScript + working-directory: cluster-ui + run: | + npx tsc --noEmit + npx eslint "**/*.{ts,tsx}" --fix + + - name: Lint JavaScript + working-directory: cluster-ui + run: npx eslint "**/*.{js,jsx}" --fix + gitleaks-cluster-ui: + name: GitLeaks Security Scan + runs-on: ubuntu-latest + needs: cluster-ui-lint + permissions: + security-events: write + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run GitLeaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + config-path: .gitleaks.toml + enable-upload-artifact: true + report-format: sarif + report-path: gitleaks-report.sarif + + cluster-ui-build: + runs-on: ubuntu-latest + needs: gitleaks-cluster-ui + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + steps: + - uses: actions/checkout@v4 + - name: Docker Build and Push + if: github.event_name != 'pull_request' + working-directory: cluster-api + env: + CLUSTER_UI_REGISTRY_URL: ${{secrets.CLUSTER_UI_REGISTRY_URL}} + CLUSTER_UI_REGISTRY_USER: ${{secrets.CLUSTER_UI_REGISTRY_USER}} + CLUSTER_UI_REGISTRY_PASSWORD: ${{secrets.CLUSTER_UI_REGISTRY_PASSWORD}} + + run: | + echo "Docker login to $REGISTRY_HOST" + + + docker login -u ${{secrets.CLUSTER_UI_REGISTRY_USER}} -p "${{secrets.CLUSTER_UI_REGISTRY_PASSWORD}}" + + echo "Building Docker image" + docker build . -t ${{secrets.CLUSTER_UI_REGISTRY_URL}}:${{ github.sha }} -t ${{secrets.CLUSTER_UI_REGISTRY_URL}}:latest + + echo "Pushing Docker image" + docker push ${{secrets.CLUSTER_UI_REGISTRY_URL}}:${{ github.sha }} + docker push ${{secrets.CLUSTER_UI_REGISTRY_URL}}:latest + + echo "Clean up" + if [ -f .id_rsa ]; then rm .id_rsa; fi + + + \ No newline at end of file diff --git a/cluster-service/Dockerfile b/cluster-service/Dockerfile index 6163e92..63c39ec 100644 --- a/cluster-service/Dockerfile +++ b/cluster-service/Dockerfile @@ -18,4 +18,4 @@ COPY . /app # Install your app COPY . . RUN pip install --no-cache-dir --upgrade -r requirements.txt -CMD python main.py +CMD python main.py \ No newline at end of file diff --git a/cluster-ui/Dockerfile b/cluster-ui/Dockerfile index c555bbf..0609dbe 100644 --- a/cluster-ui/Dockerfile +++ b/cluster-ui/Dockerfile @@ -22,4 +22,4 @@ RUN npm run build EXPOSE 3000 # 7. Run the app -CMD ["npm", "run", "preview"] +CMD ["npm", "run", "preview"] \ No newline at end of file