02 · Delivery & security

Shipping Code with Confidence.

Secure CI/CD Pipeline for Tabulae

A secure delivery pipeline for the Tabulae inventory management application, combining automated testing,dependency and secret scanning, container image analysis, and publishing to Amazon ECR.

CI and security workflows · ECR publishing from main · Manual Kubernetes deployment

  • GitHub Actions
  • Docker
  • Pytest
  • PostgreSQL
  • ESLint
  • Gitleaks
  • Trivy
  • pip-audit
  • npm audit
  • Amazon ECR
  • AWS OIDC
  • Helm
  • Kind
View repository

01Overview and objectives

Tabulae is an existing open-source inventory management application. I did not build the application itself; my work focused on the testing, security, containerization, and delivery workflows around it.

The goal was to make changes easier to validate before delivery by automating tests, code-quality checks, security scans, and container image publishing.

The challenge

The application has a Python backend, a React frontend, and a PostgreSQL database. The pipeline needed to provide a database for backend tests, validate the frontend, build container images, identify security issues, and publish images without storing long-lived AWS credentials in GitHub.

02Architecture

Secure CI/CD pipelineA GitHub push or pull request starts GitHub Actions. Quality jobs lint and test, Gitleaks scans for secrets, Docker builds the image and Trivy scans it in report mode. Helm charts are validated manually on Kind. After required jobs pass on main, the image is published to Amazon ECR using GitHub OIDC.GitHubpush / pull requestGitHub Actionsworkflow runsJOBS ON EVERY CHANGELintESLintTestsPytest (backend)Frontend testsnpmGLGitleakssecret scanningDocker buildimagesTvTrivyreport modeImagebuiltMANUAL VALIDATIONKKindlocal clusterHelmlint / templatePUBLISH · MAIN ONLYGitHub OIDCno stored AWS keysECRAmazon ECRimage registryafter required jobs pass
The CI, security and manual deployment paths.

Continuous Integration

Push or pull request → GitHub Actions

  • Backend tests using Pytest and a PostgreSQL service.
  • Frontend checks using ESLint and a production build.
  • Docker image build validation.

Security Workflows

  • Gitleaks for secret detection across Git history.
  • pip-audit and npm audit for dependency vulnerabilities.
  • Trivy scans of backend and frontend container images.

Image Publishing

Successful required checks → main branch → GitHub OIDC → Amazon ECR

Images are tagged with the commit SHA and latest, according to the configured workflow.

Kubernetes Validation

Manual deployment → Kind → Helm

The application was deployed to a local Kind cluster using Helm. A deliberately failed upgrade was used to verify Helm's --atomic rollback behavior.

The Kind deployment is a separate manual workflow, not an automated production deployment.

03How it was built

  1. Automated testing: Created a GitHub Actions CI workflow for backend tests, frontend checks, and Docker build validation.
  2. CI database: Configured a PostgreSQL 17 service with health checks and the environment required by the backend tests.
  3. Frontend validation: Added ESLint checks and a production build using Node.js 22.
  4. Security scanning: Created a separate workflow for Gitleaks, pip-audit, and npm audit.
  5. Container scanning: Added Trivy scans for both backend and frontend images, reporting HIGH and CRITICAL findings.
  6. Secure image publishing: Configured AWS authentication through GitHub OIDC, avoiding long-lived AWS access keys in the repository.
  7. Helm deployment testing: Deployed the application to Kind and tested rollback behavior using a deliberately failed Helm upgrade with --atomic.

Verified in the repository

  • Backend tests using a PostgreSQL 17 service container.
  • Frontend ESLint checks and production build.
  • Docker build validation for backend and frontend.
  • Trivy image scans for HIGH and CRITICAL vulnerabilities.
  • Separate secret and dependency scanning workflow.
  • Amazon ECR publishing through GitHub OIDC on main, after required jobs pass.
  • Helm chart for the frontend, backend, and PostgreSQL with persistent storage.

04Decisions and trade-offs

AWS OIDC Instead of Long-Lived Access Keys

The publishing workflow authenticates to AWS using GitHub's OIDC identity and an IAM role. This avoids keeping long-lived AWS access keys in GitHub repository secrets.

Publish Only After Required Checks Pass

The ECR publishing job depends on the required CI jobs and runs on the configured main branch workflow. This prevents publishing through that job when its required checks fail.

Scan Git History for Secrets

Gitleaks checks the Git history, helping identify secrets that may have been committed and later removed from the latest version of the code.

Report Trivy Findings Before Enforcing a Gate

Trivy currently reports HIGH and CRITICAL image findings without blocking the build. Enforcing a severity-based failure policy remains a potential improvement.

Isolate CI Test Configuration

The test workflow uses a dedicated test-only secret key and a temporary PostgreSQL service instead of production configuration.

05Security considerations

  • AWS authentication: GitHub OIDC for ECR publishing instead of stored long-lived AWS access keys.
  • Secret detection: Gitleaks scans Git history.
  • Dependency auditing: pip-audit and npm audit check the Python and JavaScript dependencies.
  • Container scanning: Trivy reports HIGH and CRITICAL findings for both application images.
  • Workflow permissions: The security workflow uses read-only repository permissions.
  • Test isolation: CI uses test-only configuration and a dedicated test database.

Trivy is currently configured in report mode, so its findings do not automatically fail the build.

06Challenges and troubleshooting

Python Could Not Import the Backend Application

Root cause
The application module was not available on Python's import path in the CI runner.
Resolution
Set PYTHONPATH in the test step.
Outcome
The backend test job passed on a subsequent run.
Lesson
CI must explicitly configure the environment the application needs.

Backend Tests Failed During Configuration

Root cause
The required SECRET_KEY was missing from the CI environment.
Resolution
Added a test-only secret key to the workflow rather than using a production secret.
Outcome
The tests were able to start and run against the CI database.
Lesson
Keep test configuration separate from production credentials.

Tests Could Not Resolve the Database Host

Root cause
The tests expected the hostname db_test, which the GitHub Actions runner could not resolve by default.
Resolution
Added a hostname mapping to route db_test to 127.0.0.1, where the PostgreSQL service port was published.
Outcome
Database connections succeeded and the test suite ran.
Lesson
Local Docker networking assumptions may need explicit configuration in CI.

Frontend Linting Failed

Root cause
ESLint identified an unused variable.
Resolution
Removed the unused variable.
Outcome
The frontend lint and production build steps passed.
Lesson
Automated quality checks can catch small issues before delivery.

Dependency Audits Reported Vulnerabilities

Root cause
The dependency scanners identified packages with reported vulnerabilities.
Resolution
Reviewed the findings and updated affected dependencies.
Outcome
The configured security workflow subsequently completed successfully.
Lesson
Scanning should lead to investigation and remediation, not just produce reports.

08Scope and next steps

This project covers automated CI checks, security scanning, container image publishing to Amazon ECR, and manual Kubernetes deployment and rollback testing using Helm on Kind.

It does not include automated deployment to a production Kubernetes environment.

Potential improvements

  • Make Trivy findings block builds according to a defined severity policy.
  • Automate Kubernetes deployment after successful validation and image publishing.
  • Add smoke tests to verify application health after deployment.