<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pipeline on Denomas Handbook</title><link>https://handbook.orneksirket.com/tags/pipeline/</link><description>Recent content in Pipeline on Denomas Handbook</description><generator>Hugo</generator><language>tr</language><atom:link href="https://handbook.orneksirket.com/tags/pipeline/index.xml" rel="self" type="application/rss+xml"/><item><title>CI/CD Pipeline</title><link>https://handbook.orneksirket.com/engineering/ci-cd-pipeline/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://handbook.orneksirket.com/engineering/ci-cd-pipeline/</guid><description>&lt;h1 id="cicd-pipeline"&gt;CI/CD Pipeline&lt;/h1&gt;
&lt;p&gt;Denomas, tüm projelerinde &lt;strong&gt;GitLab CI/CD&lt;/strong&gt; kullanır. Pipeline, kodun commit edilmesinden üretim ortamına deploy edilmesine kadar tüm aşamaları otomatize eder. CI/CD altyapısı &lt;code&gt;code.denomas.com&lt;/code&gt; ve &lt;code&gt;code.ilimteknoloji.com&lt;/code&gt; adreslerindeki self-hosted GitLab instance'ları üzerinde çalışır.&lt;/p&gt;
&lt;h2 id="pipeline-aşamaları"&gt;Pipeline Aşamaları&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ ┌──────────────┐
│ lint │ → │ test │ → │ build │ → │ scan │ → │ deploy-staging │ → │ deploy-prod │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ └──────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="1-lint"&gt;1. lint&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pre-commit hook doğrulaması (&lt;code&gt;pre-commit run --all-files&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Python: &lt;strong&gt;ruff&lt;/strong&gt; lint + &lt;strong&gt;ruff-format&lt;/strong&gt; kontrolü + &lt;strong&gt;mypy&lt;/strong&gt; tip kontrolü&lt;/li&gt;
&lt;li&gt;JavaScript: &lt;strong&gt;ESLint&lt;/strong&gt; (airbnb-base preset)&lt;/li&gt;
&lt;li&gt;YAML/JSON format kontrolü (&lt;strong&gt;yamllint&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Ansible: &lt;strong&gt;ansible-lint&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Docker: &lt;strong&gt;hadolint&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Shell: &lt;strong&gt;shellcheck&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Docstring kontrolü (public fonksiyonlarda zorunlu)&lt;/li&gt;
&lt;li&gt;Conventional Commit format kontrolü&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-test"&gt;2. test&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Birim testleri&lt;/strong&gt; — &lt;code&gt;pytest --cov=src --cov-fail-under=80&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entegrasyon testleri&lt;/strong&gt; — API endpoint testleri, veritabanı migration testleri&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Odoo testleri&lt;/strong&gt; — Odoo test framework ile modül testleri (&lt;code&gt;odoo-bin --test-enable&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ansible testleri&lt;/strong&gt; — &lt;code&gt;molecule test&lt;/code&gt; ile rol doğrulaması&lt;/li&gt;
&lt;li&gt;Kapsam raporu oluşturma (Cobertura formatı, GitLab MR'da görselleştirme)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-build"&gt;3. build&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Docker image oluşturma (multi-stage build)&lt;/li&gt;
&lt;li&gt;Semantic versiyon etiketi (&lt;code&gt;$CI_COMMIT_TAG&lt;/code&gt; veya &lt;code&gt;$CI_COMMIT_SHORT_SHA&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Docker image'ı GitLab Container Registry'ye push&lt;/li&gt;
&lt;li&gt;Ansible artifact'ları paketleme (roller + playbook'lar)&lt;/li&gt;
&lt;li&gt;Hugo site build (handbook ve website projeleri için)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-scan"&gt;4. scan&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SAST:&lt;/strong&gt; Bandit (Python), Semgrep (&lt;code&gt;p/owasp-top-ten&lt;/code&gt; ruleset), GitLab SAST template&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency Scan:&lt;/strong&gt; Trivy (container + dependency CVE taraması)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lisans Kontrolü:&lt;/strong&gt; Uyumsuz lisans tespiti (GPL kontrol)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Container Image Scan:&lt;/strong&gt; Trivy ile Docker image güvenlik taraması&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret Detection:&lt;/strong&gt; GitLab Secret Detection template&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-deploy-staging"&gt;5. deploy-staging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ansible playbook ile staging ortamına deploy (&lt;code&gt;ansible-playbook deploy-staging.yml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Otomatik smoke testleri (&lt;code&gt;ansible-playbook smoke-test.yml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Performans testi (&lt;strong&gt;k6&lt;/strong&gt; ile yük testi)&lt;/li&gt;
&lt;li&gt;Staging URL'i MR'a yorum olarak eklenir&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-deploy-prod"&gt;6. deploy-prod&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://handbook.orneksirket.com/engineering/release-process/"&gt;Dual-track deployment&lt;/a&gt;
 stratejisine göre&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Track 1 (SaaS):&lt;/strong&gt; &lt;code&gt;main&lt;/code&gt; merge sonrası &lt;code&gt;when: manual&lt;/code&gt; onay → canary deploy → kademeli rollout&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Track 2 (Self-Managed):&lt;/strong&gt; Release tag'i sonrası paketleme ve dağıtım&lt;/li&gt;
&lt;li&gt;Production deploy sonrası otomatik health check&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tam-gitlab-ciyml-örneği"&gt;Tam &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; Örneği&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# .gitlab-ci.yml — Denomas standart pipeline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;python:3.10-slim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;variables&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Genel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;PIP_CACHE_DIR&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$CI_PROJECT_DIR/.cache/pip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;PRE_COMMIT_HOME&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$CI_PROJECT_DIR/.cache/pre-commit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Docker&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;DOCKER_IMAGE&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$CI_REGISTRY_IMAGE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;DOCKER_TAG&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$CI_COMMIT_SHORT_SHA&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Deployment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ANSIBLE_INVENTORY&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;inventory/$CI_ENVIRONMENT_NAME&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ANSIBLE_FORCE_COLOR&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# SAST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;SAST_EXCLUDED_PATHS&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;tests/,migrations/,docs/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;SECURE_LOG_LEVEL&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;warn&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;cache&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;key&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${CI_COMMIT_REF_SLUG}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;.cache/pip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;.cache/pre-commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;.venv/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;stages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;lint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;scan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;deploy-staging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;deploy-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ─── LINT ─────────────────────────────────────────────&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;lint:pre-commit&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;lint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pip install pre-commit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pre-commit run --all-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_PIPELINE_SOURCE == &amp;#34;merge_request_event&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;develop&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;lint:mypy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;lint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pip install -r requirements-dev.txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;mypy src/ --ignore-missing-imports&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_PIPELINE_SOURCE == &amp;#34;merge_request_event&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;allow_failure&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ─── TEST ─────────────────────────────────────────────&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;test:unit&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;postgres:15-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;redis:7-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;variables&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;POSTGRES_DB&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;test_db&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;POSTGRES_USER&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;test_user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;POSTGRES_PASSWORD&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;$CI_DB_PASSWORD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;DATABASE_URL&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;postgresql://test_user:$CI_DB_PASSWORD@postgres:5432/test_db&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;REDIS_URL&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;redis://redis:6379/0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pip install -r requirements-dev.txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pytest --cov=src --cov-report=xml --cov-report=term --cov-fail-under=80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;artifacts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;reports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;coverage_report&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;coverage_format&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cobertura&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;coverage.xml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;expire_in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_PIPELINE_SOURCE == &amp;#34;merge_request_event&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;develop&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;test:integration&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;postgres:15-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;redis:7-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pip install -r requirements-dev.txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pytest tests/integration/ -v --tb=short&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_PIPELINE_SOURCE == &amp;#34;merge_request_event&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ─── BUILD ────────────────────────────────────────────&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;build:docker&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;docker:24.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;docker:24.0-dind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;docker build -t $DOCKER_IMAGE:$DOCKER_TAG -t $DOCKER_IMAGE:latest .&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;docker push $DOCKER_IMAGE:$DOCKER_TAG&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;docker push $DOCKER_IMAGE:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;develop&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;main&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_TAG&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ─── SCAN ─────────────────────────────────────────────&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;scan:bandit&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;scan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;pip install bandit[toml]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;bandit -c pyproject.toml -r src/ -f json -o bandit-report.json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;artifacts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;bandit-report.json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;expire_in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_PIPELINE_SOURCE == &amp;#34;merge_request_event&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;scan:semgrep&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;scan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;returntocorp/semgrep&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;semgrep --config=p/owasp-top-ten --config=p/python --json -o semgrep-report.json src/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;artifacts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;semgrep-report.json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;expire_in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_PIPELINE_SOURCE == &amp;#34;merge_request_event&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;scan:trivy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;scan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;aquasec/trivy:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;entrypoint&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;trivy image --exit-code 1 --severity HIGH,CRITICAL $DOCKER_IMAGE:$DOCKER_TAG&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;develop&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;main&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;include&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;template&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Security/SAST.gitlab-ci.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;template&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Security/Secret-Detection.gitlab-ci.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ─── DEPLOY STAGING ───────────────────────────────────&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;deploy_staging&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;deploy-staging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ansible/ansible-runner:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;ansible-playbook deploy-staging.yml -e &amp;#34;docker_tag=$DOCKER_TAG&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;ansible-playbook smoke-test.yml -e &amp;#34;environment=staging&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;staging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://staging.denomas.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;staging&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ─── DEPLOY PRODUCTION ───────────────────────────────&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;deploy_canary&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;deploy-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ansible/ansible-runner:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;ansible-playbook deploy-canary.yml -e &amp;#34;docker_tag=$DOCKER_TAG canary_weight=5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;canary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://canary.denomas.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;main&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;when&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;deploy_production&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stage&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;deploy-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ansible/ansible-runner:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;ansible-playbook deploy-production.yml -e &amp;#34;docker_tag=$DOCKER_TAG&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;ansible-playbook smoke-test.yml -e &amp;#34;environment=production&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;production&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://denomas.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$CI_COMMIT_BRANCH == &amp;#34;main&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;when&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;manual&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;needs&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;deploy_canary&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ortam-değişkenleri-cicd-variables"&gt;Ortam Değişkenleri (CI/CD Variables)&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Değişken&lt;/th&gt;
 &lt;th&gt;Tür&lt;/th&gt;
 &lt;th&gt;Kapsam&lt;/th&gt;
 &lt;th&gt;Açıklama&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CI_REGISTRY_USER&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected&lt;/td&gt;
 &lt;td&gt;Tüm projeler&lt;/td&gt;
 &lt;td&gt;GitLab Container Registry kullanıcı&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CI_REGISTRY_PASSWORD&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected, Masked&lt;/td&gt;
 &lt;td&gt;Tüm projeler&lt;/td&gt;
 &lt;td&gt;GitLab Container Registry parola&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CI_DB_PASSWORD&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected, Masked&lt;/td&gt;
 &lt;td&gt;Tüm projeler&lt;/td&gt;
 &lt;td&gt;Test veritabanı parolası&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ANSIBLE_SSH_KEY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected, File&lt;/td&gt;
 &lt;td&gt;Deploy projeleri&lt;/td&gt;
 &lt;td&gt;Deployment SSH anahtarı&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;SENTRY_DSN&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected&lt;/td&gt;
 &lt;td&gt;Production&lt;/td&gt;
 &lt;td&gt;Hata izleme DSN&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GRAFANA_API_KEY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected, Masked&lt;/td&gt;
 &lt;td&gt;Monitoring&lt;/td&gt;
 &lt;td&gt;Grafana dashboard API&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;VAULT_TOKEN&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Protected, Masked&lt;/td&gt;
 &lt;td&gt;Production&lt;/td&gt;
 &lt;td&gt;HashiCorp Vault erişim token&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="td-alert td-alert--md alert alert-caution" role="alert"&gt;&lt;div class="td-alert-heading alert-heading" role="heading"&gt;Sır Yönetimi&lt;/div&gt;
 &lt;div class="td-alert-body"&gt;
 &lt;p&gt;Hassas değerler &lt;strong&gt;asla&lt;/strong&gt; &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; içinde açık metin olarak yazılmaz. Tüm sırlar GitLab CI/CD Variables'da &lt;strong&gt;Protected&lt;/strong&gt; ve &lt;strong&gt;Masked&lt;/strong&gt; olarak tanımlanır. Detaylar için &lt;a href="https://handbook.orneksirket.com/engineering/architecture-principles/"&gt;Mimari Prensipler — Zero Trust&lt;/a&gt;
 bölümüne bakınız.&lt;/p&gt;</description></item><item><title>Data Engineer</title><link>https://handbook.orneksirket.com/hiring/job-families/data-engineer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://handbook.orneksirket.com/hiring/job-families/data-engineer/</guid><description>&lt;h1 id="data-engineer-veri-mühendisi"&gt;Data Engineer (Veri Mühendisi)&lt;/h1&gt;
&lt;p&gt;Veri mühendisleri, Denomas ürünlerinin veri altyapısını tasarlar ve yönetir. ETL süreçleri, veri pipeline'ları, veri ambarı ve analitik altyapıdan sorumludur.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="kullanılan-araçlar"&gt;Kullanılan Araçlar&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Araç&lt;/th&gt;
 &lt;th&gt;Kullanım Alanı&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;PostgreSQL&lt;/td&gt;
 &lt;td&gt;İlişkisel veri tabanı&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Wazuh&lt;/td&gt;
 &lt;td&gt;Log toplama, arama ve görselleştirme&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Apache Airflow&lt;/td&gt;
 &lt;td&gt;Pipeline orkestrasyon&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Python&lt;/td&gt;
 &lt;td&gt;ETL betikleri ve veri işleme&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Redis&lt;/td&gt;
 &lt;td&gt;Önbellekleme ve kuyruk yönetimi&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Git&lt;/td&gt;
 &lt;td&gt;Versiyon kontrolü&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="kariyer-seviyeleri-ve-denomas-yetkinlik-çerçevesi-gereksinimleri"&gt;Kariyer Seviyeleri ve Denomas Yetkinlik Çerçevesi Gereksinimleri&lt;/h2&gt;
&lt;h3 id="junior-data-engineer--yetkinlik-seviyesi-2"&gt;Junior Data Engineer — Yetkinlik Seviyesi 2&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Denomas Yetkinlik Çerçevesi Gereksinimleri:&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Pazarlama Performans Metrikleri</title><link>https://handbook.orneksirket.com/marketing/performans-metrikleri/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://handbook.orneksirket.com/marketing/performans-metrikleri/</guid><description>&lt;h1 id="pazarlama-performans-metrikleri"&gt;Pazarlama Performans Metrikleri&lt;/h1&gt;
&lt;p&gt;Denomas pazarlama ekibinin başarısını ölçmek için kullanılan temel performans göstergelerini (KPI) tanımlayan belgedir. Stratejik KPI'lar (pipeline katkısı, gelir etkisi, CAC), taktik KPI'lar (MQL, SQL, dönüşüm oranları, kanal bazlı lead üretimi, maliyet metrikleri), operasyonel KPI'lar (web sitesi, içerik, e-posta, sosyal medya metrikleri), ürün bazlı pazarlama metrikleri, funnel sağlık kontrolü, multi-touch attribution modeli ve raporlama takvimini kapsar.&lt;/p&gt;
&lt;div class="td-alert td-alert--md alert alert-info" role="alert"&gt;&lt;div class="td-alert-heading alert-heading" role="heading"&gt;İç Doküman&lt;/div&gt;
 &lt;div class="td-alert-body"&gt;
 &lt;p&gt;Bu konunun detayları iç handbook'ta yer almaktadır. Tam içerik için &lt;a href="https://internal.handbook.denomas.com"&gt;internal.handbook.denomas.com&lt;/a&gt;
 adresine bakınız.&lt;/p&gt;</description></item><item><title>Satış Rehberi</title><link>https://handbook.orneksirket.com/sales/sales-playbook/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://handbook.orneksirket.com/sales/sales-playbook/</guid><description>&lt;h1 id="satış-rehberi"&gt;Satış Rehberi&lt;/h1&gt;
&lt;p&gt;Bu rehber, Denomas satış sürecinin tüm aşamalarını ve her aşamada yapılması gerekenleri tanımlar. Tüm satış aktiviteleri &lt;strong&gt;Odoo CRM&lt;/strong&gt; üzerinden takip edilir ve satış ekibi koordinasyonu &lt;strong&gt;Nextcloud Talk&lt;/strong&gt; üzerinden yururulur.&lt;/p&gt;
&lt;h2 id="satış-pipeline-aşamaları"&gt;Satış Pipeline Aşamaları&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1. PROSPECT → Potansiyel müşteri tespiti ve ilk temas
2. QUALIFY → BANT niteliklendirme ve ihtiyaç teyidi
3. DEMO → Canlı ürün gösterimi
4. POC → Proof of Concept / Pilot uygulama
5. PROPOSE → Resmi teklif sunumu
6. NEGOTIATE → Müzakere ve fiyatlandırma
7. CLOSE → Sözleşme imzalama ve handoff
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="1-prospect-potansiyel-müşteri-tespiti"&gt;1. Prospect (Potansiyel Müşteri Tespiti)&lt;/h2&gt;
&lt;h3 id="kaynak-kanalları"&gt;Kaynak Kanalları&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Kanal&lt;/th&gt;
 &lt;th&gt;Açıklama&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Inbound&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Web sitesi, referans, webinar kayıtları&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Outbound&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Etkinlikler, soğuk arama, LinkedIn&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Partner&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://handbook.orneksirket.com/sales/partners/partner-program/"&gt;Partner&lt;/a&gt;
 yönlendirmeleri&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Mevcut Müşteri&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Upsell / cross-sell fırsatları&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="ilk-temas-süreci"&gt;İlk Temas Süreci&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Lead Odoo CRM'e kaydedilir&lt;/li&gt;
&lt;li&gt;24 saat içinde ilk temas yapılır&lt;/li&gt;
&lt;li&gt;Temel bilgiler toplanır (şirket büyüklüğü, sektör, bölge)&lt;/li&gt;
&lt;li&gt;Bir sonraki adım için randevu alınır&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="2-qualify-niteliklendirme"&gt;2. Qualify (Niteliklendirme)&lt;/h2&gt;
&lt;h3 id="bant-kriterleri"&gt;BANT Kriterleri&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Kriter&lt;/th&gt;
 &lt;th&gt;Soru&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Budget (Bütçe)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Proje için ayrılmış bütçe var mi? TRY/USD/EUR cinsinden beklenti nedir?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Authority (Yetki)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Karar verici kim? Teknik ve finansal onay süreci nasıl?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Need (İhtiyaç)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Mevcut acı noktalar neler? Hangi sorunlar çözüm bekliyor?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Timeline (Zaman)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Ne zaman çözüm devreye alinmak isteniyor?&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="niteliklendirme-puanlama"&gt;Niteliklendirme Puanlama&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A (Hot)&lt;/strong&gt; — 4/4 BANT kriteri pozitif, 30 gün içinde kapanma potansiyeli&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B (Warm)&lt;/strong&gt; — 3/4 kriter pozitif, 90 gün içinde kapanma potansiyeli&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C (Nurture)&lt;/strong&gt; — 2/4 kriter pozitif, uzun vadeli takip&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D (Disqualify)&lt;/strong&gt; — 1/4 veya daha az, pipeline'dan çıkarılır&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-discovery-call-framework"&gt;3. Discovery Call Framework&lt;/h2&gt;
&lt;p&gt;Discovery call, niteliklendirme aşamasinin en kritik aktivitesidir. Aşağıdaki çerçeve takip edilir:&lt;/p&gt;</description></item><item><title>Talep Oluşturma</title><link>https://handbook.orneksirket.com/marketing/talep-olusturma/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://handbook.orneksirket.com/marketing/talep-olusturma/</guid><description>&lt;h1 id="talep-oluşturma"&gt;Talep Oluşturma&lt;/h1&gt;
&lt;p&gt;Talep oluşturma (demand generation), potansiyel müşterilerde Denomas ürünlerine yönelik farkındalık ve ilgi yaratarak nitelikli satış fırsatları üretmeyi amaçlar. Bu sayfa, lead generation süreçlerini, kampanya yönetimini ve funnel optimizasyonunu tanımlar.&lt;/p&gt;
&lt;div class="td-alert td-alert--md alert alert-dse" role="alert"&gt;&lt;div class="td-alert-heading alert-heading" role="heading"&gt;@pazarlama-ekibi&lt;/div&gt;
 &lt;div class="td-alert-body"&gt;
 &lt;p&gt;Talep oluşturma stratejisi ve kampanya yönetimi @pazarlama-ekibi sorumluluğundadır. Satış ekibiyle MQL/SQL tanımları ve aktarım süreçleri ortaklaşa belirlenir.&lt;/p&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="talep-oluşturma-stratejisi"&gt;Talep Oluşturma Stratejisi&lt;/h2&gt;
&lt;h3 id="temel-prensipler"&gt;Temel Prensipler&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Nitelik &amp;gt; Nicelik&lt;/strong&gt; — Çok sayıda düşük kaliteli lead yerine, satış ekibinin zamanını verimli kullanacağı nitelikli lead üretmek&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inbound Öncelik&lt;/strong&gt; — İçerik pazarlama, SEO ve topluluk aracılığıyla gelen organik talep birincil kaynaktır&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outbound Destek&lt;/strong&gt; — Hedefli outbound kampanyalar, belirli sektör ve hesap segmentlerinde inbound'u tamamlar&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hesap Bazlı Pazarlama (ABM)&lt;/strong&gt; — Yüksek değerli hedef hesaplar için kişiselleştirilmiş kampanyalar&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Satış-Pazarlama Hizalaması&lt;/strong&gt; — MQL/SQL tanımları, aktarım süreçleri ve geri bildirim döngüsü net tanımlanmıştır&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="lead-yönetimi"&gt;Lead Yönetimi&lt;/h2&gt;
&lt;h3 id="lead-yaşam-döngüsü"&gt;Lead Yaşam Döngüsü&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Ziyaretçi → Lead → MQL → SQL → Fırsat → Müşteri
&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Aşama&lt;/th&gt;
 &lt;th&gt;Tanım&lt;/th&gt;
 &lt;th&gt;Kriter&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Ziyaretçi&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Web sitesini/içeriği ziyaret eden anonim kullanıcı&lt;/td&gt;
 &lt;td&gt;Sayfa görüntüleme&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Lead&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;İletişim bilgilerini paylaşmış kişi&lt;/td&gt;
 &lt;td&gt;Form doldurma, kayıt&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;MQL (Marketing Qualified Lead)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Pazarlama tarafından nitelikli bulunan lead&lt;/td&gt;
 &lt;td&gt;Lead puanı ≥50&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;SQL (Sales Qualified Lead)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Satış ekibi tarafından nitelikli bulunan lead&lt;/td&gt;
 &lt;td&gt;BANT kriterleri karşılanmış&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Fırsat&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Aktif satış süreci başlamış potansiyel müşteri&lt;/td&gt;
 &lt;td&gt;Teklif aşaması&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Müşteri&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Sözleşme imzalamış kurum&lt;/td&gt;
 &lt;td&gt;Kapanmış fırsat&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="bant-nitelendirme-çerçevesi"&gt;BANT Nitelendirme Çerçevesi&lt;/h3&gt;
&lt;p&gt;BANT (Budget, Authority, Need, Timeline), SQL nitelendirmesi için kullanılan çerçevedir:&lt;/p&gt;</description></item></channel></rss>