[{"data":1,"prerenderedAt":759},["ShallowReactive",2],{"/en-us/blog/tutorial-security-scanning-in-air-gapped-environments":3,"navigation-en-us":38,"banner-en-us":464,"footer-en-us":481,"Fernando Diaz":725,"next-steps-en-us":738,"footer-source-/en-us/blog/tutorial-security-scanning-in-air-gapped-environments/":753},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":27,"_id":31,"_type":32,"title":33,"_source":34,"_file":35,"_stem":36,"_extension":37},"/en-us/blog/tutorial-security-scanning-in-air-gapped-environments","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"Tutorial: Security scanning in air-gapped environments","Security scanning remains crucial even in air-gapped environments to detect internal threats, prevent data exfiltration, and maintain operational integrity. Learn how GitLab can help get air-gapped environments secure.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099301/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_1097303277_6gTk7M1DNx0tFuovupVFB1_1750099300786.jpg","https://about.gitlab.com/blog/tutorial-security-scanning-in-air-gapped-environments","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Tutorial: Security scanning in air-gapped environments\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2025-02-05\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"Fernando Diaz","2025-02-05","Air-gapped environments are computer networks or systems that are physically\nisolated from unsecured networks, such as the public internet or unsecured\nlocal area networks. This isolation is implemented as a security measure to\nprotect sensitive data and critical systems from external cyber threats by\nproviding:\n\n\n* Enhanced security: By physically isolating systems from external networks,\nair-gapped environments help prevent remote attacks, malware infections, and\nunauthorized data access. This is crucial for highly sensitive data and\ncritical systems.\n\n* Data protection: Air-gapping provides the strongest protection against\ndata exfiltration since there's no direct connection that attackers could\nuse to steal information.\n\n* Critical infrastructure protection: For systems that control vital\ninfrastructure (like power plants, water treatment facilities, or military\nsystems), air-gapping helps prevent potentially catastrophic cyber attacks.\n\n* Compliance requirements: Many regulatory frameworks require air-gapping\nfor certain types of sensitive data or critical systems, particularly in\ngovernment, healthcare, and financial sectors.\n\n* Malware protection: Without network connectivity, systems are protected\nfrom network-based malware infections and ransomware attacks.\n\n\nEven though air-gapped systems are isolated, they can still have\nvulnerabilities. Regular security scanning helps identify these weaknesses\nbefore they can be exploited. In this article, you will learn the different\nsecurity scanners GitLab provides and how they can be added/updated in a\nlimited-connectivity environment.\n\n\n## GitLab security scanners in air-gapped environments\n\n\nGitLab provides a variety of different security scanners for the complete\napplication lifecycle. The scanners that support air-gapped environments\ninclude:\n\n\n* [Static Application Security Testing\n(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/index.html#running-sast-in-an-offline-environment)\n\n* [Dynamic Application Security Testing\n(DAST](https://docs.gitlab.com/ee/user/application_security/dast/browser/configuration/offline_configuration.html))\n\n* [Secret\nDetection](https://docs.gitlab.com/ee/user/application_security/secret_detection/pipeline/index.html#offline-configuration)\n\n* [Container\nScanning](https://docs.gitlab.com/ee/user/application_security/container_scanning/index.html#running-container-scanning-in-an-offline-environment)\n\n* [Dependency\nScanning](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/index.html#offline-environment)\n\n* [API\nFuzzing](https://docs.gitlab.com/ee/user/application_security/api_fuzzing/configuration/offline_configuration.html)\n\n* [License\nScanning](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/index.html#running-in-an-offline-environment)\n\n\nBy default, GitLab Self-Managed instances pull security scanner images from\nthe public GitLab container registry (registry.gitlab.com) and store them\nwithin the [built-in local GitLab container\nregistry](https://docs.gitlab.com/ee/user/packages/container_registry/). I\nwill demonstrate this flow below by running the following pipeline that\nscans for secrets on a [sample\nproject](https://gitlab.com/gitlab-da/tutorials/security-and-governance/owasp/juice-shop):\n\n\n```yaml\n\ninclude:\n  - template: Jobs/Secret-Detection.gitlab-ci.yml\n```\n\n\nWhen running the job in an internet-connected GitLab instance the job\npasses:\n\n\n![GitLab Runner with internet access successfully pulling from external\nregistry\n\n](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099328/Blog/Content%20Images/Blog/Content%20Images/pass-1_aHR0cHM6_1750099328577.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Runner with internet access successfully pulling from\nexternal registry\u003C/i>\u003C/center>\n\n\n\u003Cbr>\u003C/br>\n\nHowever, If I disable internet access to the VM running GitLab, the\n`secret-detection` job will fail to download the container image, causing\nthe job to fail:\n\n\n![GitLab Runner without internet access failing to pull from external\nregistry](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099328/Blog/Content%20Images/Blog/Content%20Images/fail-1_aHR0cHM6_1750099328577.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Runner without internet access failing to pull from\nexternal registry\u003C/i>\u003C/center>\n\n\u003Cbr>\u003C/br>\n\n\nAlternatively, if I set my GitLab Runners’ pull image policy to\n`if-not-present` from `always`, I can load the cached version of the scanner\nif it was run before on the internet by using the image stored in our local\ndocker:\n\n\n![GitLab Runner without internet access successfully pulling from internal\nregistry\ncache](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099329/Blog/Content%20Images/Blog/Content%20Images/pass-2_aHR0cHM6_1750099328579.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Runner without internet access successfully pulling from\ninternal registry cache\u003C/i>\u003C/center>\n\n\n\u003Cbr>\u003C/br>\n\n\n### Setting up offline scanning prerequisites\n\n\nRunning these security scanners in an air-gapped environment requires the\nfollowing:\n\n\n* [GitLab Ultimate\nsubscription](https://about.gitlab.com/pricing/ultimate/)\n\n* [Offline cloud\nlicense](https://about.gitlab.com/pricing/licensing-faq/cloud-licensing/#offline-cloud-licensing)\n\n* GitLab Self-Managed cluster\n\n\nYou can follow along with this tutorial in any GitLab Self-Managed EE\ninstance (even those that are not air-gapped) to learn how to transfer and\nrun images in an air-gapped environment. In this tutorial, I will\ndemonstrate how to load scanner images onto a GitLab-EE instance running in\na Google Compute VM where I cut off the `EGRESS` to everything by\nimplementing firewall rules:\n\n\n```bash\n\n# egress firewall rule to block all outbound traffic to the internet\n\n$ gcloud compute firewall-rules create deny-internet-egress \\\n    --direction=EGRESS \\\n    --priority=1000 \\\n    --network=default \\\n    --action=DENY \\\n    --rules=all \\\n    --destination-ranges=0.0.0.0/0 \\\n    --target-tags=no-internet\n\n# Create an allow rule for internal traffic with higher priority\n\n$ gcloud compute firewall-rules create allow-internal-egress \\\n    --direction=EGRESS \\\n    --priority=900 \\\n    --network=default \\\n    --action=ALLOW \\\n    --rules=all \\\n    --destination-ranges=10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 \\\n    --target-tags=no-internet\n\n# Apply tag to VM\n\n$ gcloud compute instances add-tags YOUR_VM_NAME \\\n    --zone=YOUR_ZONE \\\n    --tags=no-internet\n```\n\n\nThen, once I SSH into my VM, you can see we cannot connect to\nregistry.gitlab.com:\n\n\n```bash\n\n# showing I can’t access the gitlab container registry\n\n$ ping registry.gitlab.com\n\nPING registry.gitlab.com (35.227.35.254) 56(84) bytes of data.\n\n^C\n\n--- registry.gitlab.com ping statistics ---\n\n3 packets transmitted, 0 received, 100% packet loss, time 2031ms\n\n```\n\n\n**Note:** I am still allowing ingress so I can copy files and SSH into the\nmachine.\n\n\n## Load security scanners in air-gapped environments\n\n\nTo use the various security scanners on air-gapped environments, the GitLab\nRunner must be able to fetch the scanner container images from GitLab’s\nbuilt-in container registry. This means that the container images for the\nsecurity scanners must be downloaded and packaged in a separate environment\nwith access to the public internet. The process of loading security scanners\nonto an air-gapped environment includes the following:\n\n\n1. Download and package container images from the public internet.\n\n2. Transfer images to offline environment.\n\n3. Load transferred images into offline container registry.\n\n\nNow let’s go over how we can implement GitLab Secret Detection in an\nair-gapped environment.\n\n\n### Download and package container images from public internet\n\n\nLet’s download the container image for secret detection and store it within\nour local container registry. Other scanner images can be found in the\n[offline deployments\ndocumentation](https://docs.gitlab.com/ee/user/application_security/offline_deployments/).\nI will be using Podman desktop to download these images, but you can use\nDocker desktop or other alternatives.\n\n\n1. Pull the GitLab Secret Detection image.\n\n\n```bash\n\n$ podman pull registry.gitlab.com/security-products/secrets:6\n\nTrying to pull registry.gitlab.com/security-products/secrets:6...\n\nGetting image source signatures\n\nCopying blob\nsha256:999745130ac045f2b1c29ecce088b43fc4a95bbb82b7960fb7b8abe0e3801bf8\n\nCopying blob\nsha256:a4f7c013bb259c146cd8455b7c3943df7ed84b157e42a2348eef16546d8179b1\n\nCopying blob\nsha256:1f3e46996e2966e4faa5846e56e76e3748b7315e2ded61476c24403d592134f0\n\nCopying blob\nsha256:400a41f248eb3c870bd2b07073632c49f1e164c8efad56ea3b24098a657ec625\n\nCopying blob\nsha256:9090f17a5a1bb80bcc6f393b0715210568dd0a7749286e3334a1a08fb32d34e6\n\nCopying blob\nsha256:c7569783959081164164780f6c1b0bbe1271ee8d291d3e07b2749ae741621ea3\n\nCopying blob\nsha256:20c7ca6108f808ad5905f6db4f7e3c02b21b69abdea8b45abfa34c0a2ba8bdb5\n\nCopying blob\nsha256:e8645a00be64d77c6ff301593ce34cd8c17ffb2b36252ca0f2588009a7918d2e\n\nCopying config\nsha256:0235ed43fc7fb2852c76e2d6196601968ae0375c72a517bef714cd712600f894\n\nWriting manifest to image destination\n\nWARNING: image platform (linux/amd64) does not match the expected platform\n(linux/arm64)\n\n0235ed43fc7fb2852c76e2d6196601968ae0375c72a517bef714cd712600f894\n\n\n$ podman images\n\nREPOSITORY                                                  TAG\nIMAGE ID      CREATED      SIZE\n\nregistry.gitlab.com/security-products/secrets               6\n0235ed43fc7f  4 hours ago  85.3 MB\n\n```\n\n\n2. Save the image as a tarball.\n\n\n```bash\n\n$ podman save -o secret-detection.tar\nregistry.gitlab.com/security-products/secrets:6\n\n$ chmod +r secret-detection.tar\n\n$ ls -al secret-detection.tar\n\n-rw-r--r--@ 1 fern  staff  85324800 Jan 10 10:25 secret-detection.tar\n\n```\n\n\nAlternatively, you can use the [official GitLab\ntemplate](https://docs.gitlab.com/ee/user/application_security/offline_deployments/#using-the-official-gitlab-template)\non an environment with internet access to download the container images\nneeded for the security scanners and save them as job artifacts or push them\nto the container registry of the project where the pipeline is executed.\n\n\n### Transfer images to offline environment\n\n\nNext, let's transfer the tarball to our air-gapped environment. This can be\ndone in several ways, depending on your needs, such as:\n\n\n* Physical media transfer\n\n* Data diodes\n\n* Guard systems\n\n* Cross-domain solutions (CDS)\n\n\nI will SCP (Secure Copy Protocol) the tarball directly to my VM that does\nnot have egress access, but does allow ingress. As this is just for\ndemonstration purposes, make sure to consult your organization's security\npolicies and transfer procedures for air-gapped environments.\n\n\n#### Verify the image is not cached\n\n\nBefore transferring the file, I’ll delete the Docker images on my GitLab\ninstance pertaining to secret detection to make sure they aren't cached:\n\n\n```bash\n\n$ docker images\n\nREPOSITORY\nTAG              IMAGE ID       CREATED        SIZE\n\nregistry.gitlab.com/security-products/secrets\n6                0235ed43fc7f   9 hours ago    84.8MB\n\nregistry.gitlab.com/security-products/secrets\n\u003Cnone>           16d88433af61   17 hours ago   74.9MB\n\n\n$ docker image rmi 16d88433af61 -f\n\nUntagged:\nregistry.gitlab.com/security-products/secrets@sha256:f331da6631d791fcd58d3f23d868475a520f50b02d64000e2faf1def66c75d48\n\nDeleted:\nsha256:16d88433af618f0b405945031de39fe40b3e8ef1bddb91ca036de0f5b32399d7\n\nDeleted:\nsha256:1bb06f72f06810e95a70039e797481736e492201f51a03b02d27db055248ab6f\n\nDeleted:\nsha256:a5ef2325ce4be9b39993ce301f8ed7aad1c854d7ee66f26a56a96967c6606510\n\nDeleted:\nsha256:f7cdac818a36d6c023763b76a6589c0db7609ca883306af4f38b819e62f29471\n\nDeleted:\nsha256:5eabf4d47287dee9887b9692d55c8b5f848b50b3b7248f67913036014e74a0e9\n\nDeleted:\nsha256:51b7cb600604c0737356f17bc02c22bac3a63697f0bf95ba7bacb5b421fdb7da\n\nDeleted:\nsha256:1546193b011d192aa769a15d3fdd55eb4e187f201f5ff7506243abb02525dc06\n\nDeleted:\nsha256:1ea72408d0484c3059cc0008539e6f494dc829caa1a97d156795687d42d9cb57\n\nDeleted:\nsha256:1313ee9da7716d85f63cfdd1129f715e9bbb6c9c0306e4708ee73672b3e40f26\n\nDeleted:\nsha256:954ebfd83406f0dfed93eb5157ba841af5426aa95d4054174fff45095fd873a1\n\n\n$ docker image rmi 0235ed43fc7f -f\n\nUntagged: registry.gitlab.com/security-products/secrets:6\n\nDeleted:\nsha256:0235ed43fc7fb2852c76e2d6196601968ae0375c72a517bef714cd712600f894\n\nDeleted:\nsha256:f05f85850cf4fac79e279d93afb6645c026de0223d07b396fce86c2f76096c1f\n\nDeleted:\nsha256:7432b0766b885144990edd3166fbabed081be71d28d186f4d525e52729f06b1f\n\nDeleted:\nsha256:2c6e3361c2ee2f43bd75fb9c7c12d981ce06df2d51a134965fa47754760efff0\n\nDeleted:\nsha256:7ad7f7245b45fbe758ebd5788e0ba268a56829715527a9a4bc51708c21af1c7f\n\nDeleted:\nsha256:3b73a621115a59564979f41552181dce07f3baa17e27428f7fff2155042a1901\n\nDeleted:\nsha256:78648c2606a7c4c76885806ed976b13e4d008940bd3d7a18b52948a6be71b60d\n\nDeleted:\nsha256:383d4a6dc5be9914878700809b4a3925379c80ab792dfe9e79d14b0c1d6b5fad\n\n```\n\n\nThen I'll rerun the job to show the failure:\n\n\n![GitLab Runner without internet access fails to pull an image from internal\nregistry\ncache](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099328/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750099328580.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Runner without internet access fails to pull an image from\ninternal registry cache\u003C/i>\u003C/center>\n\n\n#### SCP file to GitLab instance\n\n\nNow, from my local machine, I will SCP the file to my GitLab instance as\nfollows:\n\n\n```bash\n\n$ gcloud compute scp secret-detection.tar INSTANCE:~ --zone=ZONE\n\nsecret-detection.tar\n100%   81MB  21.5MB/s   00:03\n\n```\n\n\n### Load transferred images into offline container registry\n\n\nNext, I'll SSH into my VM and load the Docker image:\n\n\n```bash\n\n$ gcloud compute ssh INSTANCE --zone=ZONE\n\n\n$ sudo docker load -i secret-detection.tar\n\nc3c8e454c212: Loading layer\n[==================================================>]  2.521MB/2.521MB\n\n51e93afaeedc: Loading layer\n[==================================================>]  32.55MB/32.55MB\n\ne8a25e39bb30: Loading layer\n[==================================================>]  221.2kB/221.2kB\n\n390704968493: Loading layer\n[==================================================>]  225.8kB/225.8kB\n\n76cf57e75f63: Loading layer\n[==================================================>]  17.64MB/17.64MB\n\nc4c7a681fd10: Loading layer\n[==================================================>]  4.608kB/4.608kB\n\nf0690f406157: Loading layer\n[==================================================>]  24.01MB/24.01MB\n\nLoaded image: registry.gitlab.com/security-products/secrets:6\n\n```\n\n\n### Run the scanners\n\n\nI'll [re-run the pipeline\nmanually](https://docs.gitlab.com/ee/ci/pipelines/#run-a-pipeline-manually)\nand the scanner will be pulled from the cache. Once the pipeline completes,\nwe can see the secret detection job is successful:\n\n\n![GitLab Runner without internet access successfully pulling from internal\nregistry cache after image\nloaded](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099328/Blog/Content%20Images/Blog/Content%20Images/image7_aHR0cHM6_1750099328581.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Runner without internet access successfully pulling from\ninternal registry cache after image loaded\u003C/center>\u003C/i>\n\n\nIf you want to pull the image from a different location or you tag your\nimages in a different way, you can edit the config as follows:\n\n\n```yaml\n\ninclude:\n  - template: Jobs/Secret-Detection.gitlab-ci.yml\n\nvariables:\n  SECURE_ANALYZERS_PREFIX: \"localhost:5000/analyzers\"\n```\n\n\nSee the [offline environments\ndocumentation](https://docs.gitlab.com/ee/user/application_security/offline_deployments/)\nfor more information.\n\n\n### View scanner results\n\n\nOnce the scanner completes on the default branch, a vulnerability report is\npopulated with all the findings. The vulnerability report provides\ninformation about vulnerabilities from scans of the default branch.\n\n\nYou can access the vulnerability report by navigating to the side tab and\nselecting **Secure > Vulnerability Report**:\n\n\n![GitLab Vulnerability Report with secret detection\nfindings](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099328/Blog/Content%20Images/Blog/Content%20Images/vulnerability_report_aHR0cHM6_1750099328581.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Vulnerability Report with secret detection\nfindings\u003C/i>\u003C/center>\n\n\n\u003Cbr>\u003C/br>\n\n\nThe project’s vulnerability report provides:\n\n- totals of vulnerabilities per severity level\n\n- filters for common vulnerability attributes\n\n- details of each vulnerability, presented in tabular layout\n\n- a timestamp showing when it was updated, including a link to the latest\npipeline\n\n\nWe can see that two vulnerabilities were detected by the Secret Detection\nscanner. If we click on a vulnerability, we will be transported to its\nvulnerability page:\n\n\n![GitLab Vulnerability Page showing detailed\ninsights](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099329/Blog/Content%20Images/Blog/Content%20Images/insights_aHR0cHM6_1750099328582.png)\n\n\n\u003Ccenter>\u003Ci>GitLab Vulnerability Page showing detailed insights\u003C/center>\u003C/i>\n\n\n\u003Cbr>\u003C/br>\n\n\nThe vulnerability page provides details of the vulnerability, which can be\nused to triage and find a path to remediation. These vulnerability details\ninclude:\n\n- description\n\n- when it was detected\n\n- current status\n\n- available actions\n\n- linked issues\n\n- actions log\n\n- filename and line number of the vulnerability (if available)\n\n- severity\n\n\n## Read more\n\n\nTo learn more about GitLab and running security scanners in air-gapped\nenvironments, check out the following resources:\n\n\n* [GitLab Ultimate](https://about.gitlab.com/pricing/ultimate/)\n\n* [GitLab Security and Compliance\nSolutions](https://about.gitlab.com/solutions/application-security-testing/)\n\n* [GitLab Offline Deployments\nDocumentation](https://docs.gitlab.com/ee/user/application_security/offline_deployments/)\n\n* [GitLab Application Security\nDocumentation](https://docs.gitlab.com/ee/user/application_security/)\n","security",[23,21,24,25,26],"tutorial","public sector","DevSecOps platform","features",{"slug":28,"featured":29,"template":30},"tutorial-security-scanning-in-air-gapped-environments",true,"BlogPost","content:en-us:blog:tutorial-security-scanning-in-air-gapped-environments.yml","yaml","Tutorial Security Scanning In Air Gapped Environments","content","en-us/blog/tutorial-security-scanning-in-air-gapped-environments.yml","en-us/blog/tutorial-security-scanning-in-air-gapped-environments","yml",{"_path":39,"_dir":40,"_draft":6,"_partial":6,"_locale":7,"data":41,"_id":460,"_type":32,"title":461,"_source":34,"_file":462,"_stem":463,"_extension":37},"/shared/en-us/main-navigation","en-us",{"logo":42,"freeTrial":47,"sales":52,"login":57,"items":62,"search":391,"minimal":422,"duo":441,"pricingDeployment":450},{"config":43},{"href":44,"dataGaName":45,"dataGaLocation":46},"/","gitlab logo","header",{"text":48,"config":49},"Get free trial",{"href":50,"dataGaName":51,"dataGaLocation":46},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":53,"config":54},"Talk to sales",{"href":55,"dataGaName":56,"dataGaLocation":46},"/sales/","sales",{"text":58,"config":59},"Sign in",{"href":60,"dataGaName":61,"dataGaLocation":46},"https://gitlab.com/users/sign_in/","sign in",[63,107,202,207,312,372],{"text":64,"config":65,"cards":67,"footer":90},"Platform",{"dataNavLevelOne":66},"platform",[68,74,82],{"title":64,"description":69,"link":70},"The most comprehensive AI-powered DevSecOps Platform",{"text":71,"config":72},"Explore our Platform",{"href":73,"dataGaName":66,"dataGaLocation":46},"/platform/",{"title":75,"description":76,"link":77},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":78,"config":79},"Meet GitLab Duo",{"href":80,"dataGaName":81,"dataGaLocation":46},"/gitlab-duo/","gitlab duo ai",{"title":83,"description":84,"link":85},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":86,"config":87},"Learn more",{"href":88,"dataGaName":89,"dataGaLocation":46},"/why-gitlab/","why gitlab",{"title":91,"items":92},"Get started with",[93,98,103],{"text":94,"config":95},"Platform Engineering",{"href":96,"dataGaName":97,"dataGaLocation":46},"/solutions/platform-engineering/","platform engineering",{"text":99,"config":100},"Developer Experience",{"href":101,"dataGaName":102,"dataGaLocation":46},"/developer-experience/","Developer experience",{"text":104,"config":105},"MLOps",{"href":106,"dataGaName":104,"dataGaLocation":46},"/topics/devops/the-role-of-ai-in-devops/",{"text":108,"left":29,"config":109,"link":111,"lists":115,"footer":185},"Product",{"dataNavLevelOne":110},"solutions",{"text":112,"config":113},"View all Solutions",{"href":114,"dataGaName":110,"dataGaLocation":46},"/solutions/",[116,141,164],{"title":117,"description":118,"link":119,"items":124},"Automation","CI/CD and automation to accelerate deployment",{"config":120},{"icon":121,"href":122,"dataGaName":123,"dataGaLocation":46},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[125,129,133,137],{"text":126,"config":127},"CI/CD",{"href":128,"dataGaLocation":46,"dataGaName":126},"/solutions/continuous-integration/",{"text":130,"config":131},"AI-Assisted Development",{"href":80,"dataGaLocation":46,"dataGaName":132},"AI assisted development",{"text":134,"config":135},"Source Code Management",{"href":136,"dataGaLocation":46,"dataGaName":134},"/solutions/source-code-management/",{"text":138,"config":139},"Automated Software Delivery",{"href":122,"dataGaLocation":46,"dataGaName":140},"Automated software delivery",{"title":142,"description":143,"link":144,"items":149},"Security","Deliver code faster without compromising security",{"config":145},{"href":146,"dataGaName":147,"dataGaLocation":46,"icon":148},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[150,154,159],{"text":151,"config":152},"Application Security Testing",{"href":146,"dataGaName":153,"dataGaLocation":46},"Application security testing",{"text":155,"config":156},"Software Supply Chain Security",{"href":157,"dataGaLocation":46,"dataGaName":158},"/solutions/supply-chain/","Software supply chain security",{"text":160,"config":161},"Software Compliance",{"href":162,"dataGaName":163,"dataGaLocation":46},"/solutions/software-compliance/","software compliance",{"title":165,"link":166,"items":171},"Measurement",{"config":167},{"icon":168,"href":169,"dataGaName":170,"dataGaLocation":46},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[172,176,180],{"text":173,"config":174},"Visibility & Measurement",{"href":169,"dataGaLocation":46,"dataGaName":175},"Visibility and Measurement",{"text":177,"config":178},"Value Stream Management",{"href":179,"dataGaLocation":46,"dataGaName":177},"/solutions/value-stream-management/",{"text":181,"config":182},"Analytics & Insights",{"href":183,"dataGaLocation":46,"dataGaName":184},"/solutions/analytics-and-insights/","Analytics and insights",{"title":186,"items":187},"GitLab for",[188,193,198],{"text":189,"config":190},"Enterprise",{"href":191,"dataGaLocation":46,"dataGaName":192},"/enterprise/","enterprise",{"text":194,"config":195},"Small Business",{"href":196,"dataGaLocation":46,"dataGaName":197},"/small-business/","small business",{"text":199,"config":200},"Public Sector",{"href":201,"dataGaLocation":46,"dataGaName":24},"/solutions/public-sector/",{"text":203,"config":204},"Pricing",{"href":205,"dataGaName":206,"dataGaLocation":46,"dataNavLevelOne":206},"/pricing/","pricing",{"text":208,"config":209,"link":211,"lists":215,"feature":299},"Resources",{"dataNavLevelOne":210},"resources",{"text":212,"config":213},"View all resources",{"href":214,"dataGaName":210,"dataGaLocation":46},"/resources/",[216,249,271],{"title":217,"items":218},"Getting started",[219,224,229,234,239,244],{"text":220,"config":221},"Install",{"href":222,"dataGaName":223,"dataGaLocation":46},"/install/","install",{"text":225,"config":226},"Quick start guides",{"href":227,"dataGaName":228,"dataGaLocation":46},"/get-started/","quick setup checklists",{"text":230,"config":231},"Learn",{"href":232,"dataGaLocation":46,"dataGaName":233},"https://university.gitlab.com/","learn",{"text":235,"config":236},"Product documentation",{"href":237,"dataGaName":238,"dataGaLocation":46},"https://docs.gitlab.com/","product documentation",{"text":240,"config":241},"Best practice videos",{"href":242,"dataGaName":243,"dataGaLocation":46},"/getting-started-videos/","best practice videos",{"text":245,"config":246},"Integrations",{"href":247,"dataGaName":248,"dataGaLocation":46},"/integrations/","integrations",{"title":250,"items":251},"Discover",[252,257,261,266],{"text":253,"config":254},"Customer success stories",{"href":255,"dataGaName":256,"dataGaLocation":46},"/customers/","customer success stories",{"text":258,"config":259},"Blog",{"href":260,"dataGaName":5,"dataGaLocation":46},"/blog/",{"text":262,"config":263},"Remote",{"href":264,"dataGaName":265,"dataGaLocation":46},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":267,"config":268},"TeamOps",{"href":269,"dataGaName":270,"dataGaLocation":46},"/teamops/","teamops",{"title":272,"items":273},"Connect",[274,279,284,289,294],{"text":275,"config":276},"GitLab Services",{"href":277,"dataGaName":278,"dataGaLocation":46},"/services/","services",{"text":280,"config":281},"Community",{"href":282,"dataGaName":283,"dataGaLocation":46},"/community/","community",{"text":285,"config":286},"Forum",{"href":287,"dataGaName":288,"dataGaLocation":46},"https://forum.gitlab.com/","forum",{"text":290,"config":291},"Events",{"href":292,"dataGaName":293,"dataGaLocation":46},"/events/","events",{"text":295,"config":296},"Partners",{"href":297,"dataGaName":298,"dataGaLocation":46},"/partners/","partners",{"backgroundColor":300,"textColor":301,"text":302,"image":303,"link":307},"#2f2a6b","#fff","Insights for the future of software development",{"altText":304,"config":305},"the source promo card",{"src":306},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":308,"config":309},"Read the latest",{"href":310,"dataGaName":311,"dataGaLocation":46},"/the-source/","the source",{"text":313,"config":314,"lists":316},"Company",{"dataNavLevelOne":315},"company",[317],{"items":318},[319,324,330,332,337,342,347,352,357,362,367],{"text":320,"config":321},"About",{"href":322,"dataGaName":323,"dataGaLocation":46},"/company/","about",{"text":325,"config":326,"footerGa":329},"Jobs",{"href":327,"dataGaName":328,"dataGaLocation":46},"/jobs/","jobs",{"dataGaName":328},{"text":290,"config":331},{"href":292,"dataGaName":293,"dataGaLocation":46},{"text":333,"config":334},"Leadership",{"href":335,"dataGaName":336,"dataGaLocation":46},"/company/team/e-group/","leadership",{"text":338,"config":339},"Team",{"href":340,"dataGaName":341,"dataGaLocation":46},"/company/team/","team",{"text":343,"config":344},"Handbook",{"href":345,"dataGaName":346,"dataGaLocation":46},"https://handbook.gitlab.com/","handbook",{"text":348,"config":349},"Investor relations",{"href":350,"dataGaName":351,"dataGaLocation":46},"https://ir.gitlab.com/","investor relations",{"text":353,"config":354},"Trust Center",{"href":355,"dataGaName":356,"dataGaLocation":46},"/security/","trust center",{"text":358,"config":359},"AI Transparency Center",{"href":360,"dataGaName":361,"dataGaLocation":46},"/ai-transparency-center/","ai transparency center",{"text":363,"config":364},"Newsletter",{"href":365,"dataGaName":366,"dataGaLocation":46},"/company/contact/","newsletter",{"text":368,"config":369},"Press",{"href":370,"dataGaName":371,"dataGaLocation":46},"/press/","press",{"text":373,"config":374,"lists":375},"Contact us",{"dataNavLevelOne":315},[376],{"items":377},[378,381,386],{"text":53,"config":379},{"href":55,"dataGaName":380,"dataGaLocation":46},"talk to sales",{"text":382,"config":383},"Support portal",{"href":384,"dataGaName":385,"dataGaLocation":46},"https://support.gitlab.com","support portal",{"text":387,"config":388},"Customer portal",{"href":389,"dataGaName":390,"dataGaLocation":46},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":392,"login":393,"suggestions":400},"Close",{"text":394,"link":395},"To search repositories and projects, login to",{"text":396,"config":397},"gitlab.com",{"href":60,"dataGaName":398,"dataGaLocation":399},"search login","search",{"text":401,"default":402},"Suggestions",[403,405,409,411,415,419],{"text":75,"config":404},{"href":80,"dataGaName":75,"dataGaLocation":399},{"text":406,"config":407},"Code Suggestions (AI)",{"href":408,"dataGaName":406,"dataGaLocation":399},"/solutions/code-suggestions/",{"text":126,"config":410},{"href":128,"dataGaName":126,"dataGaLocation":399},{"text":412,"config":413},"GitLab on AWS",{"href":414,"dataGaName":412,"dataGaLocation":399},"/partners/technology-partners/aws/",{"text":416,"config":417},"GitLab on Google Cloud",{"href":418,"dataGaName":416,"dataGaLocation":399},"/partners/technology-partners/google-cloud-platform/",{"text":420,"config":421},"Why GitLab?",{"href":88,"dataGaName":420,"dataGaLocation":399},{"freeTrial":423,"mobileIcon":428,"desktopIcon":433,"secondaryButton":436},{"text":424,"config":425},"Start free trial",{"href":426,"dataGaName":51,"dataGaLocation":427},"https://gitlab.com/-/trials/new/","nav",{"altText":429,"config":430},"Gitlab Icon",{"src":431,"dataGaName":432,"dataGaLocation":427},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":429,"config":434},{"src":435,"dataGaName":432,"dataGaLocation":427},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":437,"config":438},"Get Started",{"href":439,"dataGaName":440,"dataGaLocation":427},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":442,"mobileIcon":446,"desktopIcon":448},{"text":443,"config":444},"Learn more about GitLab Duo",{"href":80,"dataGaName":445,"dataGaLocation":427},"gitlab duo",{"altText":429,"config":447},{"src":431,"dataGaName":432,"dataGaLocation":427},{"altText":429,"config":449},{"src":435,"dataGaName":432,"dataGaLocation":427},{"freeTrial":451,"mobileIcon":456,"desktopIcon":458},{"text":452,"config":453},"Back to pricing",{"href":205,"dataGaName":454,"dataGaLocation":427,"icon":455},"back to pricing","GoBack",{"altText":429,"config":457},{"src":431,"dataGaName":432,"dataGaLocation":427},{"altText":429,"config":459},{"src":435,"dataGaName":432,"dataGaLocation":427},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":465,"_dir":40,"_draft":6,"_partial":6,"_locale":7,"title":466,"button":467,"image":472,"config":476,"_id":478,"_type":32,"_source":34,"_file":479,"_stem":480,"_extension":37},"/shared/en-us/banner","is now in public beta!",{"text":468,"config":469},"Try the Beta",{"href":470,"dataGaName":471,"dataGaLocation":46},"/gitlab-duo/agent-platform/","duo banner",{"altText":473,"config":474},"GitLab Duo Agent Platform",{"src":475},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":477},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":482,"_dir":40,"_draft":6,"_partial":6,"_locale":7,"data":483,"_id":721,"_type":32,"title":722,"_source":34,"_file":723,"_stem":724,"_extension":37},"/shared/en-us/main-footer",{"text":484,"source":485,"edit":491,"contribute":496,"config":501,"items":506,"minimal":713},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":486,"config":487},"View page source",{"href":488,"dataGaName":489,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":492,"config":493},"Edit this page",{"href":494,"dataGaName":495,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":497,"config":498},"Please contribute",{"href":499,"dataGaName":500,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":502,"facebook":503,"youtube":504,"linkedin":505},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[507,554,606,650,679],{"title":203,"links":508,"subMenu":523},[509,513,518],{"text":510,"config":511},"View plans",{"href":205,"dataGaName":512,"dataGaLocation":490},"view plans",{"text":514,"config":515},"Why Premium?",{"href":516,"dataGaName":517,"dataGaLocation":490},"/pricing/premium/","why premium",{"text":519,"config":520},"Why Ultimate?",{"href":521,"dataGaName":522,"dataGaLocation":490},"/pricing/ultimate/","why ultimate",[524],{"title":525,"links":526},"Contact Us",[527,530,532,534,539,544,549],{"text":528,"config":529},"Contact sales",{"href":55,"dataGaName":56,"dataGaLocation":490},{"text":382,"config":531},{"href":384,"dataGaName":385,"dataGaLocation":490},{"text":387,"config":533},{"href":389,"dataGaName":390,"dataGaLocation":490},{"text":535,"config":536},"Status",{"href":537,"dataGaName":538,"dataGaLocation":490},"https://status.gitlab.com/","status",{"text":540,"config":541},"Terms of use",{"href":542,"dataGaName":543,"dataGaLocation":490},"/terms/","terms of use",{"text":545,"config":546},"Privacy statement",{"href":547,"dataGaName":548,"dataGaLocation":490},"/privacy/","privacy statement",{"text":550,"config":551},"Cookie preferences",{"dataGaName":552,"dataGaLocation":490,"id":553,"isOneTrustButton":29},"cookie preferences","ot-sdk-btn",{"title":108,"links":555,"subMenu":562},[556,559],{"text":25,"config":557},{"href":73,"dataGaName":558,"dataGaLocation":490},"devsecops platform",{"text":130,"config":560},{"href":80,"dataGaName":561,"dataGaLocation":490},"ai-assisted development",[563],{"title":564,"links":565},"Topics",[566,571,576,581,586,591,596,601],{"text":567,"config":568},"CICD",{"href":569,"dataGaName":570,"dataGaLocation":490},"/topics/ci-cd/","cicd",{"text":572,"config":573},"GitOps",{"href":574,"dataGaName":575,"dataGaLocation":490},"/topics/gitops/","gitops",{"text":577,"config":578},"DevOps",{"href":579,"dataGaName":580,"dataGaLocation":490},"/topics/devops/","devops",{"text":582,"config":583},"Version Control",{"href":584,"dataGaName":585,"dataGaLocation":490},"/topics/version-control/","version control",{"text":587,"config":588},"DevSecOps",{"href":589,"dataGaName":590,"dataGaLocation":490},"/topics/devsecops/","devsecops",{"text":592,"config":593},"Cloud Native",{"href":594,"dataGaName":595,"dataGaLocation":490},"/topics/cloud-native/","cloud native",{"text":597,"config":598},"AI for Coding",{"href":599,"dataGaName":600,"dataGaLocation":490},"/topics/devops/ai-for-coding/","ai for coding",{"text":602,"config":603},"Agentic AI",{"href":604,"dataGaName":605,"dataGaLocation":490},"/topics/agentic-ai/","agentic ai",{"title":607,"links":608},"Solutions",[609,611,613,618,622,625,629,632,634,637,640,645],{"text":151,"config":610},{"href":146,"dataGaName":151,"dataGaLocation":490},{"text":140,"config":612},{"href":122,"dataGaName":123,"dataGaLocation":490},{"text":614,"config":615},"Agile development",{"href":616,"dataGaName":617,"dataGaLocation":490},"/solutions/agile-delivery/","agile delivery",{"text":619,"config":620},"SCM",{"href":136,"dataGaName":621,"dataGaLocation":490},"source code management",{"text":567,"config":623},{"href":128,"dataGaName":624,"dataGaLocation":490},"continuous integration & delivery",{"text":626,"config":627},"Value stream management",{"href":179,"dataGaName":628,"dataGaLocation":490},"value stream management",{"text":572,"config":630},{"href":631,"dataGaName":575,"dataGaLocation":490},"/solutions/gitops/",{"text":189,"config":633},{"href":191,"dataGaName":192,"dataGaLocation":490},{"text":635,"config":636},"Small business",{"href":196,"dataGaName":197,"dataGaLocation":490},{"text":638,"config":639},"Public sector",{"href":201,"dataGaName":24,"dataGaLocation":490},{"text":641,"config":642},"Education",{"href":643,"dataGaName":644,"dataGaLocation":490},"/solutions/education/","education",{"text":646,"config":647},"Financial services",{"href":648,"dataGaName":649,"dataGaLocation":490},"/solutions/finance/","financial services",{"title":208,"links":651},[652,654,656,658,661,663,665,667,669,671,673,675,677],{"text":220,"config":653},{"href":222,"dataGaName":223,"dataGaLocation":490},{"text":225,"config":655},{"href":227,"dataGaName":228,"dataGaLocation":490},{"text":230,"config":657},{"href":232,"dataGaName":233,"dataGaLocation":490},{"text":235,"config":659},{"href":237,"dataGaName":660,"dataGaLocation":490},"docs",{"text":258,"config":662},{"href":260,"dataGaName":5,"dataGaLocation":490},{"text":253,"config":664},{"href":255,"dataGaName":256,"dataGaLocation":490},{"text":262,"config":666},{"href":264,"dataGaName":265,"dataGaLocation":490},{"text":275,"config":668},{"href":277,"dataGaName":278,"dataGaLocation":490},{"text":267,"config":670},{"href":269,"dataGaName":270,"dataGaLocation":490},{"text":280,"config":672},{"href":282,"dataGaName":283,"dataGaLocation":490},{"text":285,"config":674},{"href":287,"dataGaName":288,"dataGaLocation":490},{"text":290,"config":676},{"href":292,"dataGaName":293,"dataGaLocation":490},{"text":295,"config":678},{"href":297,"dataGaName":298,"dataGaLocation":490},{"title":313,"links":680},[681,683,685,687,689,691,693,697,702,704,706,708],{"text":320,"config":682},{"href":322,"dataGaName":315,"dataGaLocation":490},{"text":325,"config":684},{"href":327,"dataGaName":328,"dataGaLocation":490},{"text":333,"config":686},{"href":335,"dataGaName":336,"dataGaLocation":490},{"text":338,"config":688},{"href":340,"dataGaName":341,"dataGaLocation":490},{"text":343,"config":690},{"href":345,"dataGaName":346,"dataGaLocation":490},{"text":348,"config":692},{"href":350,"dataGaName":351,"dataGaLocation":490},{"text":694,"config":695},"Sustainability",{"href":696,"dataGaName":694,"dataGaLocation":490},"/sustainability/",{"text":698,"config":699},"Diversity, inclusion and belonging (DIB)",{"href":700,"dataGaName":701,"dataGaLocation":490},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":353,"config":703},{"href":355,"dataGaName":356,"dataGaLocation":490},{"text":363,"config":705},{"href":365,"dataGaName":366,"dataGaLocation":490},{"text":368,"config":707},{"href":370,"dataGaName":371,"dataGaLocation":490},{"text":709,"config":710},"Modern Slavery Transparency Statement",{"href":711,"dataGaName":712,"dataGaLocation":490},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":714},[715,717,719],{"text":540,"config":716},{"href":542,"dataGaName":543,"dataGaLocation":490},{"text":545,"config":718},{"href":547,"dataGaName":548,"dataGaLocation":490},{"text":550,"config":720},{"dataGaName":552,"dataGaLocation":490,"id":553,"isOneTrustButton":29},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[726],{"_path":727,"_dir":728,"_draft":6,"_partial":6,"_locale":7,"content":729,"config":733,"_id":735,"_type":32,"title":18,"_source":34,"_file":736,"_stem":737,"_extension":37},"/en-us/blog/authors/fernando-diaz","authors",{"name":18,"config":730},{"headshot":731,"ctfId":732},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659556/Blog/Author%20Headshots/fern_diaz.png","fjdiaz",{"template":734},"BlogAuthor","content:en-us:blog:authors:fernando-diaz.yml","en-us/blog/authors/fernando-diaz.yml","en-us/blog/authors/fernando-diaz",{"_path":739,"_dir":40,"_draft":6,"_partial":6,"_locale":7,"header":740,"eyebrow":741,"blurb":742,"button":743,"secondaryButton":747,"_id":749,"_type":32,"title":750,"_source":34,"_file":751,"_stem":752,"_extension":37},"/shared/en-us/next-steps","Start shipping better software faster","50%+ of the Fortune 100 trust GitLab","See what your team can do with the intelligent\n\n\nDevSecOps platform.\n",{"text":48,"config":744},{"href":745,"dataGaName":51,"dataGaLocation":746},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":53,"config":748},{"href":55,"dataGaName":56,"dataGaLocation":746},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":754,"content":755,"config":758,"_id":31,"_type":32,"title":33,"_source":34,"_file":35,"_stem":36,"_extension":37},{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},{"title":9,"description":10,"authors":756,"heroImage":11,"date":19,"body":20,"category":21,"tags":757},[18],[23,21,24,25,26],{"slug":28,"featured":29,"template":30},1761814435290]