// Engineering Log

Secure Development: Part 1 — CI/CD: From Manual Deployments to Automated Deployments

Published on 2026-09-22

// Fast route

This article belongs to the topic Deploy and reliability.

CI/CD is the practice where every code change is automatically built, tested and delivered to the server. Instead of the manual sequence “copy files, restart the service and check that nothing broke”, this work is performed by a program according to a description stored in the repository alongside the code.

This part starts the series on secure development. All the following checks — secret scanning, static code analysis, dependency and container image checks — are integrated into the pipeline, so you have to start with it.

CI, CD and CD again

  • Continuous Integration (Continuous Integration). After each git push the code is built and tests are run. A bug is discovered minutes after the commit, not on release day.
  • Continuous Delivery (Continuous Delivery). Each successful build is ready for deployment, but a person gives the command to deploy.
  • Continuous Deployment (Continuous Deployment). A successful build is deployed to the server automatically, without human intervention.

Small teams usually prefer the second model: everything is checked automatically, and deployment is triggered with a single button.

What a pipeline consists of

  • A description file in the repository: .gitlab-ci.yml, .github/workflows/*.yml, .gitea/workflows/*.yaml or Jenkinsfile.
  • Stages and jobs. Stages are executed in order; jobs within a stage run in parallel if there are enough runners.
  • Runner — a program that executes jobs. GitLab.com and GitHub.com provide cloud runners; on a self-hosted GitLab or Gitea server you need to install and register a runner yourself.
  • Variables and secrets are set in the project settings, not in the pipeline file.

Tools

GitLab CI is built into GitLab — both cloud GitLab.com and the self-hosted edition. The pipeline is described in .gitlab-ci.yml at the repository root. On your own GitLab server jobs will run only after installing and registering GitLab Runner.

GitHub Actions is built into GitHub. Pipeline files live in .github/workflows, and there is a large marketplace of ready-made actions for common steps.

Gitea Actions appeared in Gitea 1.19, and have been enabled by default since version 1.21. The syntax is mostly compatible with GitHub Actions; files are placed in .gitea/workflows/, and jobs are executed by the separate Gitea Runner program. This is a lightweight option for a company that needs its own Git server with built-in automation.

Jenkins is a separate automation server: pipelines are described in a Jenkinsfile, and functionality is extended with plugins. It is very flexible, but you are responsible for installation, updates and plugin compatibility. It is usually chosen where it is already in long-term use.

Minimal working pipeline

Example for GitLab CI: tests on every change and deployment only from the main branch.

yaml
stages:
  - test
  - deploy

test:
  stage: test
  image: python:3.13-slim
  script:
    - pip install -r requirements.txt
    - pytest

deploy:
  stage: deploy
  script:
    - ./deploy.sh
  environment: production
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      when: manual

The deploy job appears only on the main branch and waits for manual start — that’s Continuous Delivery. If you remove when: manual, you get Continuous Deployment.

Same for GitHub Actions — file .github/workflows/ci.yml:

yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    container: python:3.13-slim
    steps:
      - uses: actions/checkout@v6
      - run: pip install -r requirements.txt
      - run: pytest

Almost the same file works for Gitea Actions, only placed in .gitea/workflows/.

Where in the pipeline security checks occur

WhereWhat is checkedPart of the cycle
On the developer before commit and the first pipeline jobPasswords and keys in codePart 2 — Secrets
With testsVulnerable patterns in your own codePart 3 — SAST
With testsKnown vulnerabilities and licenses of dependenciesPart 4 — SCA
Image buildReproducibility, cache, secrets during buildPart 5 — Dockerfile
After build and at runtimeImage vulnerabilities, container privilegesPart 6 — Containers

A check is useful only if it can stop the pipeline: warnings that don’t affect anything quickly stop being read. A reasonable approach is to enable the check in report mode, review the findings, and then make it mandatory.

Pipeline secrets and access

  • Passwords and keys are stored in protected project variables (in GitLab — masked and protected, in GitHub — secrets), not in the YAML file.
  • Create a separate user and key for deployment with minimal permissions — only what’s necessary for the deployment.
  • Deployment is allowed only from the main branch.
  • A runner on a private server should not run jobs of other projects: Gitea documentation explicitly warns not to use untrusted runners or to provide your runners to untrusted instances.

GitOps

For Kubernetes, the GitOps approach is widespread: the desired state of the cluster is described in Git, and a special agent in the cluster (Argo CD or Flux) brings the cluster to that description. In this case the pipeline does not deploy the application directly, but only updates the manifests in the repository. For one or two servers without Kubernetes this is unnecessary complexity — a normal deployment step is enough.

What to consider in Russia

  • It’s not possible to pay for foreign GitHub and GitLab.com plans with a card from a Russian bank: Visa and Mastercard have not worked outside Russia since March 2022.
  • Independence from external services is provided by a self-hosted Git server — GitLab on your own server or Gitea with Gitea Actions — and runners on your own machines. This option requires administration, but code, builds and secrets remain under your control.

Common mistakes

  • Passwords in the pipeline file. They end up in Git history and are visible to everyone who has access to the repository.
  • Checks that do not stop the build. Their results are not reviewed.
  • Long pipeline. If a build takes half an hour, developers stop waiting for results. Caching dependencies and parallel jobs help.
  • Deploying from any branch. Experimental code reaches the production server.
  • One runner with production access for all projects. A bug or compromise in one project opens access to the others.

Pipeline setup for a specific project — from initial tests to deployment to your own servers — is included in the CI/CD setup service.

// Similar task

If you are dealing with something similar

This article belongs to one of the main working topics. You can keep reading on the topic, go to the homepage to understand what I do, or open the service pages directly.

Article topic

Deploy and reliability

Docker, CI/CD, releases, monitoring, observability, and incident handling.

Typical tasks behind this topic

  • Set up deployment without manual chaos
  • Add monitoring, alerts, and baseline observability
  • Investigate incidents and stabilize production

// Next step

If you need help with this topic, not just another article, it is better to go straight to the service page. The homepage and topic collection stay available as secondary routes.

Open services

// Reviews

Related reviews

I came with an expensive request to configure a VPS server, but during the consultation Mikhail suggested a much simpler, more affordable solution. In the end I saved time and money. Mikhail — a true expert who works for the client's result, not for the fee. I recommend him!

I came with an expensive request to configure a VPS server, but during the consultation Mikhail suggested a much simpler and more cost-effective solution. In the end I saved budget and time. Mikhail — a true expert who …

kfhzasorin

VPS setup, server setup

2026-05-12 · ★ 5/5

// Contact

Need help?

Get in touch with me and I'll help solve the problem

I reply within one business day (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirm that you are not a bot.

Write and get a quick reply