diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml new file mode 100644 index 0000000..1f0889d --- /dev/null +++ b/.github/workflows/docker-build-push.yml @@ -0,0 +1,76 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - main + - beta + - dev + paths: + - 'src/**' + - 'helm/Chart.yaml' + - 'config.yaml' + - 'Dockerfile' + - 'requirements.txt' + - 'entrypoint.sh' + - '.github/workflows/docker-build-push.yml' + tags: + - 'v*.*.*' + release: + types: [published] + workflow_dispatch: + +env: + REGISTRY: ${{ vars.DOCKER_REGISTRY }} + IMAGE_NAME: ${{ vars.DOCKER_IMAGE_NAME }} + +jobs: + build-and-push: + runs-on: self-hosted + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract appVersion from Chart.yaml + id: chart_version + run: | + APP_VERSION=$(grep '^appVersion:' helm/Chart.yaml | awk '{print $2}' | tr -d '"') + echo "version=$APP_VERSION" >> $GITHUB_OUTPUT + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=${{ steps.chart_version.outputs.version }},enable={{is_default_branch}} + type=raw,value=${{ steps.chart_version.outputs.version }}-${{ github.ref_name }},enable=${{ github.ref_name != 'main' }} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max + + - name: Image digest + run: echo ${{ steps.meta.outputs.digest }} diff --git a/.github/workflows/helm-package-push.yml b/.github/workflows/helm-package-push.yml new file mode 100644 index 0000000..8cd119a --- /dev/null +++ b/.github/workflows/helm-package-push.yml @@ -0,0 +1,75 @@ +name: Package and Push Helm Chart + +on: + push: + branches: + - main + - beta + - dev + paths: + - 'helm/**' + tags: + - 'v*' + release: + types: + - published + - created + workflow_dispatch: + +env: + REGISTRY: ${{ vars.DOCKER_REGISTRY }} + +jobs: + package-and-push: + runs-on: self-hosted + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: 'latest' + + - name: Log in to Container Registry + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username ${{ github.actor }} --password-stdin + + - name: Extract version from Chart.yaml + id: version + run: | + VERSION=$(grep '^version:' ./helm/Chart.yaml | awk '{print $2}' | tr -d '"') + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Package Helm chart + run: | + helm package ./helm + + - name: Push Helm chart to registry + run: | + CHART_VERSION=$(grep '^version:' ./helm/Chart.yaml | awk '{print $2}') + CHART_FILE=$(grep '^name:' ./helm/Chart.yaml | awk '{print $2}') + CHART_PATH="${CHART_FILE}-${CHART_VERSION}.tgz" + + # Determine tag based on branch + if [[ "${{ github.ref_name }}" == "main" ]]; then + TAG="${{ steps.version.outputs.version }}" + helm push "$CHART_PATH" oci://${{ env.REGISTRY }}/$CHART_FILE:$TAG + helm push "$CHART_PATH" oci://${{ env.REGISTRY }}/$CHART_FILE:latest + else + TAG="${{ steps.version.outputs.version }}-${{ github.ref_name }}" + helm push "$CHART_PATH" oci://${{ env.REGISTRY }}/$CHART_FILE:$TAG + fi + + - name: Chart pushed + run: | + CHART_FILE=$(grep '^name:' ./helm/Chart.yaml | awk '{print $2}') + if [[ "${{ github.ref_name }}" == "main" ]]; then + echo "Chart pushed: $CHART_FILE:${{ steps.version.outputs.version }} and $CHART_FILE:latest" + else + echo "Chart pushed: $CHART_FILE:${{ steps.version.outputs.version }}-${{ github.ref_name }}" + fi diff --git a/.github/workflows/kubernetes-validation.yml b/.github/workflows/kubernetes-validation.yml new file mode 100644 index 0000000..de5e1cd --- /dev/null +++ b/.github/workflows/kubernetes-validation.yml @@ -0,0 +1,57 @@ +name: Kubernetes Validation + +on: + pull_request: + branches: + - main + - beta + - dev + paths: + - 'kubernetes/**' + - 'helm/**' + - '.github/workflows/kubernetes-validation.yml' + +permissions: + contents: read + +jobs: + validate-manifests: + name: Validate Kubernetes Manifests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate YAML syntax + run: | + for manifest in kubernetes/**/*.yaml; do + if [ -f "$manifest" ]; then + echo "Validating YAML syntax: $manifest" + python3 -c "import yaml, sys; yaml.safe_load(open('$manifest'))" || exit 1 + fi + done + + - name: Validate manifest structure + run: | + for manifest in kubernetes/**/*.yaml; do + if [ -f "$manifest" ]; then + echo "Checking $manifest" + if ! grep -q "kind:" "$manifest"; then + echo "Error: $manifest does not contain a Kubernetes kind" + exit 1 + fi + fi + done + + validate-helm: + name: Validate Helm Chart + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: azure/setup-helm@v4 + + - name: Helm lint + run: helm lint ./helm + + - name: Helm template validation + run: helm template krawl ./helm > /tmp/helm-output.yaml diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..48bc45d --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,56 @@ +name: PR Checks + +on: + pull_request: + branches: + - main + - beta + - dev + +permissions: + contents: read + pull-requests: read + +jobs: + lint-and-test: + name: Lint & Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install black flake8 pylint pytest + + - name: Black format check + run: | + if [ -n "$(black --check src/ 2>&1 | grep -v 'Oh no')" ]; then + echo "Run 'black src/' to format code" + black --diff src/ + exit 1 + fi + + - name: Flake8 lint + run: flake8 src/ --max-line-length=120 --extend-ignore=E203,W503 + + - name: Pylint check + run: pylint src/ --fail-under=7.0 || true + + - name: Run tests + run: pytest tests/ -v || true + + build-docker: + name: Build Docker + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t krawl:test . diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 0000000..732b1b7 --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,59 @@ +name: Security Scan + +on: + pull_request: + branches: + - main + - beta + - dev + +permissions: + contents: read + +jobs: + security-checks: + name: Security & Dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install bandit safety + + - name: Bandit security check + run: | + bandit -r src/ -f txt | tee bandit-report.txt + + # Extract HIGH severity (not confidence) - look for the severity section + SEVERITY_SECTION=$(sed -n '/Total issues (by severity):/,/Total issues (by confidence):/p' bandit-report.txt) + HIGH_COUNT=$(echo "$SEVERITY_SECTION" | grep "High:" | grep -o "[0-9]*" | head -1) + + if [ -z "$HIGH_COUNT" ]; then + HIGH_COUNT=0 + fi + + if [ "$HIGH_COUNT" -gt 0 ]; then + echo "Found $HIGH_COUNT HIGH severity security issues" + exit 1 + fi + echo "✓ No HIGH severity security issues found" + + - name: Safety check for dependencies + run: safety check --json || true + + - name: Trivy vulnerability scan + uses: aquasecurity/trivy-action@master + with: + scan-type: 'fs' + scan-ref: '.' + format: 'table' + severity: 'CRITICAL,HIGH' + exit-code: '1' diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 3fe5d8a..94decfd 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,15 +1,15 @@ -apiVersion: v2 -name: krawl-chart -description: A Helm chart for Krawl honeypot server -type: application -version: 0.1.2 -appVersion: "1.0.0" -keywords: - - honeypot - - security - - krawl -maintainers: - - name: blessedrebus -home: https://github.com/blessedrebus/krawl -sources: - - https://github.com/blessedrebus/krawl +apiVersion: v2 +name: krawl-chart +description: A Helm chart for Krawl honeypot server +type: application +version: 0.1.3 +appVersion: "0.1.6" +keywords: + - honeypot + - security + - krawl +maintainers: + - name: blessedrebus +home: https://github.com/blessedrebus/krawl +sources: + - https://github.com/blessedrebus/krawl