[{"data":1,"prerenderedAt":1432},["ShallowReactive",2],{"/blog/how-to-protect-your-source-code-with-gitlab-and-jscrambler":3,"navigation-en-us":636,"banner-en-us":1064,"footer-en-us":1074,"blog-post-authors-en-us-Pedro Fortuna|Sam Kerr":1317,"blog-related-posts-en-us-how-to-protect-your-source-code-with-gitlab-and-jscrambler":1343,"blog-promotions-en-us":1369,"next-steps-en-us":1422},{"id":4,"title":5,"authors":6,"body":9,"category":615,"date":616,"description":617,"extension":618,"externalUrl":619,"faq":619,"featured":620,"heroImage":621,"meta":622,"navigation":139,"path":623,"seo":624,"slug":628,"stem":629,"tags":630,"template":634,"updatedDate":619,"__hash__":635},"blogPosts/en-us/blog/how-to-protect-your-source-code-with-gitlab-and-jscrambler.md","How to protect your source code with GitLab and Jscrambler",[7,8],"Pedro Fortuna","Sam Kerr",{"type":10,"value":11,"toc":604},"minimark",[12,22,31,36,39,48,51,55,58,61,66,69,87,91,106,115,123,185,194,201,204,208,223,265,271,349,363,366,372,490,499,508,517,528,532,535,542,545,549,555,580,584,587,600],[13,14,15,16,21],"p",{},"Development teams are building, testing, and shipping code faster than ever before. Today, we know that security has a role to play at the early stages of the ",[17,18,20],"a",{"href":19},"/topics/devops/","DevOps workflow",", but these security controls are mostly centered around finding and fixing bugs and vulnerabilities during development.",[13,23,24,25,30],{},"In this tutorial, we will explore the importance of protecting client-side application code at runtime and guide you through implementing it in your GitLab instance using the integration with ",[17,26,29],{"href":27,"rel":28},"https://jscrambler.com/",[],"Jscrambler",".",[32,33,35],"h2",{"id":34},"the-importance-of-runtime-code-protection","The importance of runtime code protection",[13,37,38],{},"With web and mobile applications dealing with increasingly sensitive data, addressing the application's attack surface requires considering additional threats that are not directly linked to vulnerabilities.",[13,40,41,42,47],{},"This concern has been widely covered in NIST, ISO 27001, and some of the latest iterations of OWASP guides, such as the ",[17,43,46],{"href":44,"rel":45},"https://mobile-security.gitbook.io/masvs/",[],"Mobile Application Security Verification Standard",". These information security standards highlight that attackers who gain unwarranted access to the application's source code may be able to retrieve proprietary code, find ways to bypass app restrictions, and make more progress while planning/automating data exfiltration attacks.",[13,49,50],{},"As such, it's important that companies implement an additional security layer (on top of application security best practices) to tackle the threats of tampering and reverse engineering of an application's source code.",[32,52,54],{"id":53},"getting-started-with-jscrambler-gitlab","Getting started with Jscrambler + GitLab",[13,56,57],{},"A robust code protection approach must include multiple layers to raise the bar for reverse-engineering and tampering attempts. Jscrambler achieves this by using a combination of code protection techniques, including obfuscation, code locks, runtime protection, and threat monitoring.",[13,59,60],{},"Let's see how you can easily set up this layered source code protection using Jscrambler in your GitLab instance.",[62,63,65],"h3",{"id":64},"what-you-need-for-the-jscrambler-integration","What you need for the Jscrambler integration",[13,67,68],{},"To use this integration with Jscrambler, make sure that you meet the following prerequisites:",[70,71,72,76,84],"ul",{},[73,74,75],"li",{},"A JavaScript-based project, as Jscrambler can protect JavaScript-based web and hybrid mobile apps",[73,77,78,79],{},"A ",[17,80,83],{"href":81,"rel":82},"https://jscrambler.com/signup",[],"Jscrambler account",[73,85,86],{},"A GitLab instance where the Jscrambler integration will run",[62,88,90],{"id":89},"how-to-configure-jscrambler","How to configure Jscrambler",[13,92,93,94,99,100,105],{},"The first step of this integration is to define the Jscrambler code protection techniques you want to use. The best way to do this is through the ",[17,95,98],{"href":96,"rel":97},"https://app.jscrambler.com/",[],"Jscrambler web app",". You can either select one of the pre-defined templates or pick techniques one by one. Review ",[17,101,104],{"href":102,"rel":103},"https://blog.jscrambler.com/jscrambler-101-first-use/",[],"the Jscrambler guide"," for further instructions on choosing Jscrambler techniques. No matter what you choose, download Jscrambler's JSON configuration file by clicking the download button next to the Application Settings, as shown below.",[13,107,108,114],{},[109,110],"img",{"alt":111,"src":112,"title":113},"Jscrambler_download_JSON","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398594/blog/Content%20Images/jscrambler-app-download-json.gif","How to download Jscrambler's JSON config.","\nHow to download Jscrambler's JSON config.",[13,116,117,118,122],{},"Place the file you just downloaded in your project's root folder and rename it to ",[119,120,121],"code",{},".jscramblerrc",". Now, open the file and make sure you remove the access and secret keys from this configuration file by removing the following lines.",[124,125,130],"pre",{"className":126,"code":127,"language":128,"meta":129,"style":129},"language-json shiki shiki-themes github-light","\n \"keys\": {\n   \"accessKey\": \"***********************\",\n   \"secretKey\": \"***********************\"\n },\n\n","json","",[119,131,132,141,152,168,179],{"__ignoreMap":129},[133,134,137],"span",{"class":135,"line":136},"line",1,[133,138,140],{"emptyLinePlaceholder":139},true,"\n",[133,142,144,148],{"class":135,"line":143},2,[133,145,147],{"class":146},"sYBdl"," \"keys\"",[133,149,151],{"class":150},"sgsFI",": {\n",[133,153,155,159,162,165],{"class":135,"line":154},3,[133,156,158],{"class":157},"sYu0t","   \"accessKey\"",[133,160,161],{"class":150},": ",[133,163,164],{"class":146},"\"***********************\"",[133,166,167],{"class":150},",\n",[133,169,171,174,176],{"class":135,"line":170},4,[133,172,173],{"class":157},"   \"secretKey\"",[133,175,161],{"class":150},[133,177,178],{"class":146},"\"***********************\"\n",[133,180,182],{"class":135,"line":181},5,[133,183,184],{"class":150}," },\n",[13,186,187,188,193],{},"This will prevent having hardcoded API keys, which could pose security issues. You should store these API keys using the ",[17,189,192],{"href":190,"rel":191},"https://docs.gitlab.com/ci/variables/",[],"GitLab CI environment variables",", as shown below.",[13,195,196,200],{},[109,197],{"alt":198,"src":199},"Jscrambler API keys as GitLab environment variables","https://docs.jscrambler.com/637a78d94e016c8be1866edb0627f2bc.png","\nWhere to score Jscrambler's API keys in GitLab.",[13,202,203],{},"And that's all you need from Jscrambler's side!",[62,205,207],{"id":206},"configuring-a-jscrambler-job-inside-gitlab-ci","Configuring a Jscrambler job inside GitLab CI",[13,209,210,211,214,215,218,219,222],{},"Start by checking you have placed the ",[119,212,213],{},".gitlab-ci.yml"," file at the root of your project. Inside this file, you will need to define your ",[119,216,217],{},"build"," stage, as well as add a new ",[119,220,221],{},"protect"," stage, as shown below.",[124,224,228],{"className":225,"code":226,"language":227,"meta":129,"style":129},"language-yml shiki shiki-themes github-light","stages:\n - build\n - protect\n # - deploy\n # ...\n\n","yml",[119,229,230,239,247,254,260],{"__ignoreMap":129},[133,231,232,236],{"class":135,"line":136},[133,233,235],{"class":234},"shJU0","stages",[133,237,238],{"class":150},":\n",[133,240,241,244],{"class":135,"line":143},[133,242,243],{"class":150}," - ",[133,245,246],{"class":146},"build\n",[133,248,249,251],{"class":135,"line":154},[133,250,243],{"class":150},[133,252,253],{"class":146},"protect\n",[133,255,256],{"class":135,"line":170},[133,257,259],{"class":258},"sAwPA"," # - deploy\n",[133,261,262],{"class":135,"line":181},[133,263,264],{"class":258}," # ...\n",[13,266,267,268,270],{},"The ",[119,269,217],{}," stage should be configured as follows:",[124,272,274],{"className":225,"code":273,"language":227,"meta":129,"style":129},"build:production:\n stage: build\n artifacts:\n   when: on_success\n   paths:\n     - build\n script:\n   - npm i\n   - npm run build\n\n",[119,275,276,283,292,299,309,316,324,332,341],{"__ignoreMap":129},[133,277,278,281],{"class":135,"line":136},[133,279,280],{"class":234},"build:production",[133,282,238],{"class":150},[133,284,285,288,290],{"class":135,"line":143},[133,286,287],{"class":234}," stage",[133,289,161],{"class":150},[133,291,246],{"class":146},[133,293,294,297],{"class":135,"line":154},[133,295,296],{"class":234}," artifacts",[133,298,238],{"class":150},[133,300,301,304,306],{"class":135,"line":170},[133,302,303],{"class":234},"   when",[133,305,161],{"class":150},[133,307,308],{"class":146},"on_success\n",[133,310,311,314],{"class":135,"line":181},[133,312,313],{"class":234},"   paths",[133,315,238],{"class":150},[133,317,319,322],{"class":135,"line":318},6,[133,320,321],{"class":150},"     - ",[133,323,246],{"class":146},[133,325,327,330],{"class":135,"line":326},7,[133,328,329],{"class":234}," script",[133,331,238],{"class":150},[133,333,335,338],{"class":135,"line":334},8,[133,336,337],{"class":150},"   - ",[133,339,340],{"class":146},"npm i\n",[133,342,344,346],{"class":135,"line":343},9,[133,345,337],{"class":150},[133,347,348],{"class":146},"npm run build\n",[13,350,351,352,355,356,359,360,362],{},"This configuration will run the ",[119,353,354],{},"npm run build"," command, which is a standard way of building your app to production, placing the resulting production files in the ",[119,357,358],{},"/build"," folder. Plus, it ensures that the ",[119,361,358],{}," folder becomes available as a GitLab CI artifact so that it can be used later in other jobs.",[13,364,365],{},"Here, make sure that you set the build commands and build folder according to your own project, as these may vary.",[13,367,368,369,371],{},"Next, configure the ",[119,370,221],{}," stage as shown below:",[124,373,375],{"className":225,"code":374,"language":227,"meta":129,"style":129},"build:production:obfuscated:\n stage: protect\n before_script:\n   - npm i -g jscrambler\n dependencies:\n   - build:production\n artifacts:\n   name: \"$CI_JOB_NAME\"\n   when: on_success\n   paths:\n     - build\n   expire_in: 1 week\n script:\n   # By default, all artifacts from previous stages are passed to each job.\n   - jscrambler -a $JSCRAMBLER_ACCESS_KEY -s $JSCRAMBLER_SECRET_KEY -o ./ build/**/*.*\n\n",[119,376,377,384,392,399,406,413,420,426,436,444,451,458,469,476,482],{"__ignoreMap":129},[133,378,379,382],{"class":135,"line":136},[133,380,381],{"class":234},"build:production:obfuscated",[133,383,238],{"class":150},[133,385,386,388,390],{"class":135,"line":143},[133,387,287],{"class":234},[133,389,161],{"class":150},[133,391,253],{"class":146},[133,393,394,397],{"class":135,"line":154},[133,395,396],{"class":234}," before_script",[133,398,238],{"class":150},[133,400,401,403],{"class":135,"line":170},[133,402,337],{"class":150},[133,404,405],{"class":146},"npm i -g jscrambler\n",[133,407,408,411],{"class":135,"line":181},[133,409,410],{"class":234}," dependencies",[133,412,238],{"class":150},[133,414,415,417],{"class":135,"line":318},[133,416,337],{"class":150},[133,418,419],{"class":146},"build:production\n",[133,421,422,424],{"class":135,"line":326},[133,423,296],{"class":234},[133,425,238],{"class":150},[133,427,428,431,433],{"class":135,"line":334},[133,429,430],{"class":234},"   name",[133,432,161],{"class":150},[133,434,435],{"class":146},"\"$CI_JOB_NAME\"\n",[133,437,438,440,442],{"class":135,"line":343},[133,439,303],{"class":234},[133,441,161],{"class":150},[133,443,308],{"class":146},[133,445,447,449],{"class":135,"line":446},10,[133,448,313],{"class":234},[133,450,238],{"class":150},[133,452,454,456],{"class":135,"line":453},11,[133,455,321],{"class":150},[133,457,246],{"class":146},[133,459,461,464,466],{"class":135,"line":460},12,[133,462,463],{"class":234},"   expire_in",[133,465,161],{"class":150},[133,467,468],{"class":146},"1 week\n",[133,470,472,474],{"class":135,"line":471},13,[133,473,329],{"class":234},[133,475,238],{"class":150},[133,477,479],{"class":135,"line":478},14,[133,480,481],{"class":258},"   # By default, all artifacts from previous stages are passed to each job.\n",[133,483,485,487],{"class":135,"line":484},15,[133,486,337],{"class":150},[133,488,489],{"class":146},"jscrambler -a $JSCRAMBLER_ACCESS_KEY -s $JSCRAMBLER_SECRET_KEY -o ./ build/**/*.*\n",[13,491,492,493,498],{},"This stage starts by installing the Jscrambler npm package globally. Next, it is configured to execute Jscrambler at the end of each new production build process. Typically, you will want to ensure that Jscrambler is the last stage of your build process, because Jscrambler transforms the source code extensively and can also add ",[17,494,497],{"href":495,"rel":496},"https://docs.jscrambler.com/code-integrity/documentation/transformations/self-defending",[],"anti-tampering protections",". This means changing the files after they have been protected by Jscrambler may break the app functionality.",[13,500,501,502,504,505,507],{},"This ",[119,503,221],{}," stage is configured to access the Jscrambler API keys that have been loaded as GitLab environment variables. Finally, the output of the protection is placed into the same ",[119,506,358],{}," folder and made available as a GitLab CI artifact for posterior use (e.g., a deploy job).",[13,509,510,511,516],{},"Note that while this example shows how to use the Jscrambler CLI client to protect the code, Jscrambler is compatible with ",[17,512,515],{"href":513,"rel":514},"https://docs.jscrambler.com/code-integrity/documentation/api/clients",[],"other clients",", such as Grunt, Gulp, webpack, Ember, and Metro (React Native).",[13,518,519,520,523,524,527],{},"And, that's all there is to it! You can configure your ",[119,521,522],{},"deploy"," stage as usual, which should access the contents of the ",[119,525,526],{},"build/"," folder and ensure your protected files are available in a live production environment.",[62,529,531],{"id":530},"checking-the-protection-result","Checking the protection result",[13,533,534],{},"As a final (optional) step, you might want to check the live app and see what its source code looks like. You can do that easily by using a browser debugger and opening the files from the \"Sources\" tab. The protected code should look completely unintelligible, similar to the one shown below.",[13,536,537,541],{},[109,538],{"alt":539,"src":540},"Source code protected by Jscrambler","https://i.imgur.com/HXLZyFh.png","\nExample of murky source code protected by Jscrambler.",[13,543,544],{},"Just bear in mind that, in case you are using Jscrambler's anti-debugging transformations, your browser debugger will likely crash or derail the app execution. This is intended behavior, which is very useful to prevent reverse-engineering of the code.",[32,546,548],{"id":547},"final-thoughts","Final thoughts",[13,550,551,552,554],{},"As we saw in this tutorial, setting up this integration between Jscrambler and GitLab is very straightforward. It introduces a new ",[119,553,221],{}," stage where the JavaScript source code is protected by Jscrambler before deployment.",[13,556,557,558,562,563,568,569,574,575,30],{},"Jscrambler goes well beyond JavaScript obfuscation since it provides runtime protection techniques such as ",[17,559,561],{"href":495,"rel":560},[],"self defending"," and ",[17,564,567],{"href":565,"rel":566},"https://docs.jscrambler.com/code-integrity/documentation/transformations/self-healing",[],"self healing",", which provide anti-tampering and anti-debugging capabilities, as well as ",[17,570,573],{"href":571,"rel":572},"https://docs.jscrambler.com/code-integrity/documentation/client-side-countermeasures",[],"code locks",". For more details about Jscrambler transformations, review ",[17,576,579],{"href":577,"rel":578},"https://docs.jscrambler.com/",[],"Jscrambler's documentation page",[32,581,583],{"id":582},"watch-the-demo","Watch the demo",[13,585,586],{},"More of a video person? Watch the demo on how to protect your source code using GitLab and Jscrambler.",[588,589,592,593],"figure",{"className":590},[591],"video_container","\n  ",[594,595,599],"iframe",{"src":596,"frameBorder":597,"allowFullScreen":598},"https://www.youtube-nocookie.com/embed/aBx2Vtbe-1w","0","true"," ",[601,602,603],"style",{},"html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":129,"searchDepth":143,"depth":143,"links":605},[606,607,613,614],{"id":34,"depth":143,"text":35},{"id":53,"depth":143,"text":54,"children":608},[609,610,611,612],{"id":64,"depth":154,"text":65},{"id":89,"depth":154,"text":90},{"id":206,"depth":154,"text":207},{"id":530,"depth":154,"text":531},{"id":547,"depth":143,"text":548},{"id":582,"depth":143,"text":583},"engineering","2021-06-09","Learn how to seamlessly protect your source code at build time in just a few steps.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669529/Blog/Hero%20Images/gitlab-jscrambler-blog-post-protecting-source-code.png",{},"/en-us/blog/how-to-protect-your-source-code-with-gitlab-and-jscrambler",{"title":5,"description":617,"ogTitle":5,"ogDescription":617,"noIndex":620,"ogImage":621,"ogUrl":625,"ogSiteName":626,"ogType":627,"canonicalUrls":625},"https://about.gitlab.com/blog/how-to-protect-your-source-code-with-gitlab-and-jscrambler","https://about.gitlab.com","article","how-to-protect-your-source-code-with-gitlab-and-jscrambler","en-us/blog/how-to-protect-your-source-code-with-gitlab-and-jscrambler",[631,632,633],"DevOps","security","inside GitLab","BlogPost","LpqnZCbnNtfrwyphVfR8w1iJ4wyN2I_3nXn9cQIWvwc",{"logo":637,"freeTrial":642,"sales":647,"login":652,"items":657,"search":984,"minimal":1015,"duo":1034,"switchNav":1043,"pricingDeployment":1054},{"config":638},{"href":639,"dataGaName":640,"dataGaLocation":641},"/","gitlab logo","header",{"text":643,"config":644},"Get free trial",{"href":645,"dataGaName":646,"dataGaLocation":641},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":648,"config":649},"Request a demo",{"href":650,"dataGaName":651,"dataGaLocation":641},"/sales/?contact-topic=request-demo","sales",{"text":653,"config":654},"Sign in",{"href":655,"dataGaName":656,"dataGaLocation":641},"https://gitlab.com/users/sign_in/","sign in",[658,687,787,792,906,962],{"text":659,"config":660,"menu":662},"Platform",{"dataNavLevelOne":661},"platform",{"type":663,"columns":664},"cards",[665,671,679],{"title":659,"description":666,"link":667},"The intelligent orchestration platform for DevSecOps",{"text":668,"config":669},"Explore our Platform",{"href":670,"dataGaName":661,"dataGaLocation":641},"/platform/",{"title":672,"description":673,"link":674},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":675,"config":676},"Meet GitLab Duo",{"href":677,"dataGaName":678,"dataGaLocation":641},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":680,"description":681,"link":682},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":683,"config":684},"Learn more",{"href":685,"dataGaName":686,"dataGaLocation":641},"/why-gitlab/","why gitlab",{"text":688,"left":139,"config":689,"menu":691},"Product",{"dataNavLevelOne":690},"solutions",{"type":692,"link":693,"columns":697,"feature":766},"lists",{"text":694,"config":695},"View all Solutions",{"href":696,"dataGaName":690,"dataGaLocation":641},"/solutions/",[698,722,745],{"title":699,"description":700,"link":701,"items":706},"Automation","CI/CD and automation to accelerate deployment",{"config":702},{"icon":703,"href":704,"dataGaName":705,"dataGaLocation":641},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[707,711,714,718],{"text":708,"config":709},"CI/CD",{"href":710,"dataGaLocation":641,"dataGaName":708},"/solutions/continuous-integration/",{"text":672,"config":712},{"href":677,"dataGaLocation":641,"dataGaName":713},"gitlab duo agent platform - product menu",{"text":715,"config":716},"Source Code Management",{"href":717,"dataGaLocation":641,"dataGaName":715},"/solutions/source-code-management/",{"text":719,"config":720},"Automated Software Delivery",{"href":704,"dataGaLocation":641,"dataGaName":721},"Automated software delivery",{"title":723,"description":724,"link":725,"items":730},"Security","Deliver code faster without compromising security",{"config":726},{"href":727,"dataGaName":728,"dataGaLocation":641,"icon":729},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[731,735,740],{"text":732,"config":733},"Application Security Testing",{"href":727,"dataGaName":734,"dataGaLocation":641},"Application security testing",{"text":736,"config":737},"Software Supply Chain Security",{"href":738,"dataGaLocation":641,"dataGaName":739},"/solutions/supply-chain/","Software supply chain security",{"text":741,"config":742},"Software Compliance",{"href":743,"dataGaName":744,"dataGaLocation":641},"/solutions/software-compliance/","software compliance",{"title":746,"link":747,"items":752},"Measurement",{"config":748},{"icon":749,"href":750,"dataGaName":751,"dataGaLocation":641},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[753,757,761],{"text":754,"config":755},"Visibility & Measurement",{"href":750,"dataGaLocation":641,"dataGaName":756},"Visibility and Measurement",{"text":758,"config":759},"Value Stream Management",{"href":760,"dataGaLocation":641,"dataGaName":758},"/solutions/value-stream-management/",{"text":762,"config":763},"Analytics & Insights",{"href":764,"dataGaLocation":641,"dataGaName":765},"/solutions/analytics-and-insights/","Analytics and insights",{"title":767,"type":692,"items":768},"GitLab for",[769,775,781],{"text":770,"config":771},"Enterprise",{"icon":772,"href":773,"dataGaLocation":641,"dataGaName":774},"Building","/enterprise/","enterprise",{"text":776,"config":777},"Small Business",{"icon":778,"href":779,"dataGaLocation":641,"dataGaName":780},"Work","/small-business/","small business",{"text":782,"config":783},"Public Sector",{"icon":784,"href":785,"dataGaLocation":641,"dataGaName":786},"Organization","/solutions/public-sector/","public sector",{"text":788,"config":789},"Pricing",{"href":790,"dataGaName":791,"dataGaLocation":641,"dataNavLevelOne":791},"/pricing/","pricing",{"text":793,"config":794,"menu":796},"Resources",{"dataNavLevelOne":795},"resources",{"type":692,"link":797,"columns":801,"feature":895},{"text":798,"config":799},"View all resources",{"href":800,"dataGaName":795,"dataGaLocation":641},"/resources/",[802,835,862],{"title":803,"items":804},"Getting started",[805,810,815,820,825,830],{"text":806,"config":807},"Install",{"href":808,"dataGaName":809,"dataGaLocation":641},"/install/","install",{"text":811,"config":812},"Quick start guides",{"href":813,"dataGaName":814,"dataGaLocation":641},"/get-started/","quick setup checklists",{"text":816,"config":817},"Learn",{"href":818,"dataGaLocation":641,"dataGaName":819},"https://university.gitlab.com/","learn",{"text":821,"config":822},"Product documentation",{"href":823,"dataGaName":824,"dataGaLocation":641},"https://docs.gitlab.com/","product documentation",{"text":826,"config":827},"Best practice videos",{"href":828,"dataGaName":829,"dataGaLocation":641},"/getting-started-videos/","best practice videos",{"text":831,"config":832},"Integrations",{"href":833,"dataGaName":834,"dataGaLocation":641},"/integrations/","integrations",{"title":836,"items":837},"Discover",[838,843,848,853,857],{"text":839,"config":840},"Customer success stories",{"href":841,"dataGaName":842,"dataGaLocation":641},"/customers/","customer success stories",{"text":844,"config":845},"Blog",{"href":846,"dataGaName":847,"dataGaLocation":641},"/blog/","blog",{"text":849,"config":850},"Demo Hub",{"href":851,"dataGaName":852,"dataGaLocation":641},"/demo-hub/","demo hub",{"text":854,"config":855},"The Source",{"href":856,"dataGaName":847,"dataGaLocation":641},"/the-source/",{"text":858,"config":859},"Remote",{"href":860,"dataGaName":861,"dataGaLocation":641},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":863,"items":864},"Connect",[865,870,875,880,885,890],{"text":866,"config":867},"GitLab Services",{"href":868,"dataGaName":869,"dataGaLocation":641},"/services/","services",{"text":871,"config":872},"Contribute",{"href":873,"dataGaName":874,"dataGaLocation":641},"https://contributors.gitlab.com","contribute",{"text":876,"config":877},"Community",{"href":878,"dataGaName":879,"dataGaLocation":641},"/community/","community",{"text":881,"config":882},"Forum",{"href":883,"dataGaName":884,"dataGaLocation":641},"https://forum.gitlab.com/","forum",{"text":886,"config":887},"Events",{"href":888,"dataGaName":889,"dataGaLocation":641},"/events/","events",{"text":891,"config":892},"Partners",{"href":893,"dataGaName":894,"dataGaLocation":641},"/partners/","partners",{"config":896,"title":899,"text":900,"link":901},{"background":897,"textColor":898},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":902,"config":903},"Read the latest",{"href":904,"dataGaName":905,"dataGaLocation":641},"/whats-new/","whats new",{"text":907,"config":908,"menu":910},"Company",{"dataNavLevelOne":909},"company",{"type":692,"columns":911},[912],{"items":913},[914,919,925,927,932,937,942,947,952,957],{"text":915,"config":916},"About",{"href":917,"dataGaName":918,"dataGaLocation":641},"/company/","about",{"text":920,"config":921,"footerGa":924},"Jobs",{"href":922,"dataGaName":923,"dataGaLocation":641},"/jobs/","jobs",{"dataGaName":923},{"text":886,"config":926},{"href":888,"dataGaName":889,"dataGaLocation":641},{"text":928,"config":929},"Leadership",{"href":930,"dataGaName":931,"dataGaLocation":641},"/company/team/e-group/","leadership",{"text":933,"config":934},"Handbook",{"href":935,"dataGaName":936,"dataGaLocation":641},"https://handbook.gitlab.com/","handbook",{"text":938,"config":939},"Investor relations",{"href":940,"dataGaName":941,"dataGaLocation":641},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":943,"config":944},"Trust Center",{"href":945,"dataGaName":946,"dataGaLocation":641},"/security/","trust center",{"text":948,"config":949},"AI Transparency Center",{"href":950,"dataGaName":951,"dataGaLocation":641},"/ai-transparency-center/","ai transparency center",{"text":953,"config":954},"Newsletter",{"href":955,"dataGaName":956,"dataGaLocation":641},"/company/contact/#contact-forms","newsletter",{"text":958,"config":959},"Press",{"href":960,"dataGaName":961,"dataGaLocation":641},"/press/","press",{"text":963,"config":964,"menu":965},"Contact us",{"dataNavLevelOne":909},{"type":692,"columns":966},[967],{"items":968},[969,974,979],{"text":970,"config":971},"Talk to sales",{"href":972,"dataGaName":973,"dataGaLocation":641},"/sales/","talk to sales",{"text":975,"config":976},"Support portal",{"href":977,"dataGaName":978,"dataGaLocation":641},"https://support.gitlab.com/hc/en-us","support portal",{"text":980,"config":981},"Customer portal",{"href":982,"dataGaName":983,"dataGaLocation":641},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":985,"login":986,"suggestions":993},"Close",{"text":987,"link":988},"To search repositories and projects, login to",{"text":989,"config":990},"gitlab.com",{"href":655,"dataGaName":991,"dataGaLocation":992},"search login","search",{"text":994,"default":995},"Suggestions",[996,998,1002,1004,1008,1012],{"text":672,"config":997},{"href":677,"dataGaName":672,"dataGaLocation":992},{"text":999,"config":1000},"Code Suggestions (AI)",{"href":1001,"dataGaName":999,"dataGaLocation":992},"/solutions/code-suggestions/",{"text":708,"config":1003},{"href":710,"dataGaName":708,"dataGaLocation":992},{"text":1005,"config":1006},"GitLab on AWS",{"href":1007,"dataGaName":1005,"dataGaLocation":992},"/partners/technology-partners/aws/",{"text":1009,"config":1010},"GitLab on Google Cloud",{"href":1011,"dataGaName":1009,"dataGaLocation":992},"/partners/technology-partners/google-cloud-platform/",{"text":1013,"config":1014},"Why GitLab?",{"href":685,"dataGaName":1013,"dataGaLocation":992},{"freeTrial":1016,"mobileIcon":1021,"desktopIcon":1026,"secondaryButton":1029},{"text":1017,"config":1018},"Start free trial",{"href":1019,"dataGaName":646,"dataGaLocation":1020},"https://gitlab.com/-/trials/new/","nav",{"altText":1022,"config":1023},"Gitlab Icon",{"src":1024,"dataGaName":1025,"dataGaLocation":1020},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1022,"config":1027},{"src":1028,"dataGaName":1025,"dataGaLocation":1020},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1030,"config":1031},"Get Started",{"href":1032,"dataGaName":1033,"dataGaLocation":1020},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1035,"mobileIcon":1039,"desktopIcon":1041},{"text":1036,"config":1037},"Learn more about GitLab Duo",{"href":677,"dataGaName":1038,"dataGaLocation":1020},"gitlab duo",{"altText":1022,"config":1040},{"src":1024,"dataGaName":1025,"dataGaLocation":1020},{"altText":1022,"config":1042},{"src":1028,"dataGaName":1025,"dataGaLocation":1020},{"button":1044,"mobileIcon":1049,"desktopIcon":1051},{"text":1045,"config":1046},"/switch",{"href":1047,"dataGaName":1048,"dataGaLocation":1020},"#contact","switch",{"altText":1022,"config":1050},{"src":1024,"dataGaName":1025,"dataGaLocation":1020},{"altText":1022,"config":1052},{"src":1053,"dataGaName":1025,"dataGaLocation":1020},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1055,"mobileIcon":1060,"desktopIcon":1062},{"text":1056,"config":1057},"Back to pricing",{"href":790,"dataGaName":1058,"dataGaLocation":1020,"icon":1059},"back to pricing","GoBack",{"altText":1022,"config":1061},{"src":1024,"dataGaName":1025,"dataGaLocation":1020},{"altText":1022,"config":1063},{"src":1028,"dataGaName":1025,"dataGaLocation":1020},{"title":1065,"titleMobile":1066,"button":1067,"config":1072},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":683,"config":1068},{"href":1069,"dataGaName":1070,"dataGaLocation":1071},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1073,"disabled":620},"release",{"data":1075},{"text":1076,"source":1077,"edit":1083,"contribute":1088,"config":1093,"items":1098,"minimal":1306},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1078,"config":1079},"View page source",{"href":1080,"dataGaName":1081,"dataGaLocation":1082},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1084,"config":1085},"Edit this page",{"href":1086,"dataGaName":1087,"dataGaLocation":1082},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1089,"config":1090},"Please contribute",{"href":1091,"dataGaName":1092,"dataGaLocation":1082},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1094,"facebook":1095,"youtube":1096,"linkedin":1097},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1099,1146,1198,1242,1274],{"title":788,"links":1100,"subMenu":1115},[1101,1105,1110],{"text":1102,"config":1103},"View plans",{"href":790,"dataGaName":1104,"dataGaLocation":1082},"view plans",{"text":1106,"config":1107},"Why Premium?",{"href":1108,"dataGaName":1109,"dataGaLocation":1082},"/pricing/premium/","why premium",{"text":1111,"config":1112},"Why Ultimate?",{"href":1113,"dataGaName":1114,"dataGaLocation":1082},"/pricing/ultimate/","why ultimate",[1116],{"title":1117,"links":1118},"Contact Us",[1119,1122,1124,1126,1131,1136,1141],{"text":1120,"config":1121},"Contact sales",{"href":972,"dataGaName":651,"dataGaLocation":1082},{"text":975,"config":1123},{"href":977,"dataGaName":978,"dataGaLocation":1082},{"text":980,"config":1125},{"href":982,"dataGaName":983,"dataGaLocation":1082},{"text":1127,"config":1128},"Status",{"href":1129,"dataGaName":1130,"dataGaLocation":1082},"https://status.gitlab.com/","status",{"text":1132,"config":1133},"Terms of use",{"href":1134,"dataGaName":1135,"dataGaLocation":1082},"/terms/","terms of use",{"text":1137,"config":1138},"Privacy statement",{"href":1139,"dataGaName":1140,"dataGaLocation":1082},"/privacy/","privacy statement",{"text":1142,"config":1143},"Cookie preferences",{"dataGaName":1144,"dataGaLocation":1082,"id":1145,"isOneTrustButton":139},"cookie preferences","ot-sdk-btn",{"title":688,"links":1147,"subMenu":1156},[1148,1152],{"text":1149,"config":1150},"DevSecOps platform",{"href":670,"dataGaName":1151,"dataGaLocation":1082},"devsecops platform",{"text":1153,"config":1154},"AI-Assisted Development",{"href":677,"dataGaName":1155,"dataGaLocation":1082},"ai-assisted development",[1157],{"title":1158,"links":1159},"Topics",[1160,1165,1170,1173,1178,1183,1188,1193],{"text":1161,"config":1162},"CICD",{"href":1163,"dataGaName":1164,"dataGaLocation":1082},"/topics/ci-cd/","cicd",{"text":1166,"config":1167},"GitOps",{"href":1168,"dataGaName":1169,"dataGaLocation":1082},"/topics/gitops/","gitops",{"text":631,"config":1171},{"href":19,"dataGaName":1172,"dataGaLocation":1082},"devops",{"text":1174,"config":1175},"Version Control",{"href":1176,"dataGaName":1177,"dataGaLocation":1082},"/topics/version-control/","version control",{"text":1179,"config":1180},"DevSecOps",{"href":1181,"dataGaName":1182,"dataGaLocation":1082},"/topics/devsecops/","devsecops",{"text":1184,"config":1185},"Cloud Native",{"href":1186,"dataGaName":1187,"dataGaLocation":1082},"/topics/cloud-native/","cloud native",{"text":1189,"config":1190},"AI for Coding",{"href":1191,"dataGaName":1192,"dataGaLocation":1082},"/topics/devops/ai-for-coding/","ai for coding",{"text":1194,"config":1195},"Agentic AI",{"href":1196,"dataGaName":1197,"dataGaLocation":1082},"/topics/agentic-ai/","agentic ai",{"title":1199,"links":1200},"Solutions",[1201,1203,1205,1210,1214,1217,1221,1224,1226,1229,1232,1237],{"text":732,"config":1202},{"href":727,"dataGaName":732,"dataGaLocation":1082},{"text":721,"config":1204},{"href":704,"dataGaName":705,"dataGaLocation":1082},{"text":1206,"config":1207},"Agile development",{"href":1208,"dataGaName":1209,"dataGaLocation":1082},"/solutions/agile-delivery/","agile delivery",{"text":1211,"config":1212},"SCM",{"href":717,"dataGaName":1213,"dataGaLocation":1082},"source code management",{"text":1161,"config":1215},{"href":710,"dataGaName":1216,"dataGaLocation":1082},"continuous integration & delivery",{"text":1218,"config":1219},"Value stream management",{"href":760,"dataGaName":1220,"dataGaLocation":1082},"value stream management",{"text":1166,"config":1222},{"href":1223,"dataGaName":1169,"dataGaLocation":1082},"/solutions/gitops/",{"text":770,"config":1225},{"href":773,"dataGaName":774,"dataGaLocation":1082},{"text":1227,"config":1228},"Small business",{"href":779,"dataGaName":780,"dataGaLocation":1082},{"text":1230,"config":1231},"Public sector",{"href":785,"dataGaName":786,"dataGaLocation":1082},{"text":1233,"config":1234},"Education",{"href":1235,"dataGaName":1236,"dataGaLocation":1082},"/solutions/education/","education",{"text":1238,"config":1239},"Financial services",{"href":1240,"dataGaName":1241,"dataGaLocation":1082},"/solutions/finance/","financial services",{"title":793,"links":1243},[1244,1246,1248,1250,1253,1255,1258,1260,1262,1264,1266,1268,1270,1272],{"text":806,"config":1245},{"href":808,"dataGaName":809,"dataGaLocation":1082},{"text":811,"config":1247},{"href":813,"dataGaName":814,"dataGaLocation":1082},{"text":816,"config":1249},{"href":818,"dataGaName":819,"dataGaLocation":1082},{"text":821,"config":1251},{"href":823,"dataGaName":1252,"dataGaLocation":1082},"docs",{"text":844,"config":1254},{"href":846,"dataGaName":847,"dataGaLocation":1082},{"text":1256,"config":1257},"What's new",{"href":904,"dataGaName":905,"dataGaLocation":1082},{"text":839,"config":1259},{"href":841,"dataGaName":842,"dataGaLocation":1082},{"text":858,"config":1261},{"href":860,"dataGaName":861,"dataGaLocation":1082},{"text":866,"config":1263},{"href":868,"dataGaName":869,"dataGaLocation":1082},{"text":871,"config":1265},{"href":873,"dataGaName":874,"dataGaLocation":1082},{"text":876,"config":1267},{"href":878,"dataGaName":879,"dataGaLocation":1082},{"text":881,"config":1269},{"href":883,"dataGaName":884,"dataGaLocation":1082},{"text":886,"config":1271},{"href":888,"dataGaName":889,"dataGaLocation":1082},{"text":891,"config":1273},{"href":893,"dataGaName":894,"dataGaLocation":1082},{"title":907,"links":1275},[1276,1278,1280,1282,1284,1286,1290,1295,1297,1299,1301],{"text":915,"config":1277},{"href":917,"dataGaName":909,"dataGaLocation":1082},{"text":920,"config":1279},{"href":922,"dataGaName":923,"dataGaLocation":1082},{"text":928,"config":1281},{"href":930,"dataGaName":931,"dataGaLocation":1082},{"text":933,"config":1283},{"href":935,"dataGaName":936,"dataGaLocation":1082},{"text":938,"config":1285},{"href":940,"dataGaName":941,"dataGaLocation":1082},{"text":1287,"config":1288},"Sustainability",{"href":1289,"dataGaName":1287,"dataGaLocation":1082},"/sustainability/",{"text":1291,"config":1292},"Diversity, inclusion and belonging (DIB)",{"href":1293,"dataGaName":1294,"dataGaLocation":1082},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":943,"config":1296},{"href":945,"dataGaName":946,"dataGaLocation":1082},{"text":953,"config":1298},{"href":955,"dataGaName":956,"dataGaLocation":1082},{"text":958,"config":1300},{"href":960,"dataGaName":961,"dataGaLocation":1082},{"text":1302,"config":1303},"Modern Slavery Transparency Statement",{"href":1304,"dataGaName":1305,"dataGaLocation":1082},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1307},[1308,1311,1314],{"text":1309,"config":1310},"Terms",{"href":1134,"dataGaName":1135,"dataGaLocation":1082},{"text":1312,"config":1313},"Cookies",{"dataGaName":1144,"dataGaLocation":1082,"id":1145,"isOneTrustButton":139},{"text":1315,"config":1316},"Privacy",{"href":1139,"dataGaName":1140,"dataGaLocation":1082},[1318,1331],{"id":1319,"title":7,"body":619,"config":1320,"content":1322,"description":619,"extension":227,"meta":1326,"navigation":139,"path":1327,"seo":1328,"stem":1329,"__hash__":1330},"blogAuthors/en-us/blog/authors/pedro-fortuna.yml",{"template":1321},"BlogAuthor",{"name":7,"config":1323},{"headshot":1324,"ctfId":1325},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659488/Blog/Author%20Headshots/gitlab-logo-extra-whitespace.png","7JwB4WZYF19OKwOo4yk5n4",{},"/en-us/blog/authors/pedro-fortuna",{},"en-us/blog/authors/pedro-fortuna","tat-xdu47MNjny0M03KJsvl-f5fCwj0JD9GaCb3N3ns",{"id":1332,"title":8,"body":619,"config":1333,"content":1334,"description":619,"extension":227,"meta":1338,"navigation":139,"path":1339,"seo":1340,"stem":1341,"__hash__":1342},"blogAuthors/en-us/blog/authors/sam-kerr.yml",{"template":1321},{"name":8,"config":1335},{"headshot":1336,"ctfId":1337},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668841/Blog/Author%20Headshots/stkerr-headshot.jpg","stkerr",{},"/en-us/blog/authors/sam-kerr",{},"en-us/blog/authors/sam-kerr","Uy_fuPl-EwaUBm9ppfxsmwgZvhXQR9HumvuLsv4cbko",[1344,1353,1361],{"title":1345,"description":1346,"heroImage":1347,"category":615,"date":1348,"authors":1349,"slug":1352,"externalUrl":619},"Confidential AI for GitLab Self-Hosted","Give developers AI coding agents in GitLab Duo without source code leaving a hardware-encrypted boundary — no GPUs needed.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773866173/vte9qh8rriznvyclhkes.png","2026-08-06",[1350,1351],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1354,"description":1355,"heroImage":1356,"category":615,"date":1357,"authors":1358,"slug":1360,"externalUrl":619},"Green DevOps: Why carbon measurement belongs in your CI/CD pipeline","CI/CD pipelines have a hidden carbon cost. Here's why measuring it matters, and how you can get started with Eco CI and Carmen in GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-07-09",[1359],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1362,"description":1363,"heroImage":1364,"category":615,"date":1365,"authors":1366,"slug":1368,"externalUrl":619},"How to build CI/CD observability at scale","This practical guide to GitLab pipeline analytics helps self-managed users gain operational insights using Prometheus and Grafana.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28",[1367],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1370},[1371,1385,1397,1408],{"id":1372,"categories":1373,"header":1375,"text":1376,"button":1377,"image":1382},"ai-modernization",[1374],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1378,"config":1379},"Get your AI maturity score",{"href":1380,"dataGaName":1381,"dataGaLocation":847},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1383},{"src":1384},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1386,"categories":1387,"header":1389,"text":1376,"button":1390,"image":1394},"devops-modernization",[1388,1182],"product","Are you just managing tools or shipping innovation?",{"text":1391,"config":1392},"Get your DevOps maturity score",{"href":1393,"dataGaName":1381,"dataGaLocation":847},"/assessments/devops-modernization-assessment/",{"config":1395},{"src":1396},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1398,"categories":1399,"header":1400,"text":1376,"button":1401,"image":1405},"security-modernization",[632],"Are you trading speed for security?",{"text":1402,"config":1403},"Get your security maturity score",{"href":1404,"dataGaName":1381,"dataGaLocation":847},"/assessments/security-modernization-assessment/",{"config":1406},{"src":1407},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1409,"paths":1410,"header":1413,"text":1414,"button":1415,"image":1420},"github-azure-migration",[1411,1412],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1416,"config":1417},"See how GitLab compares to GitHub",{"href":1418,"dataGaName":1419,"dataGaLocation":847},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1421},{"src":1396},{"header":1423,"blurb":1424,"button":1425,"secondaryButton":1430},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1426,"config":1427},"Get your free trial",{"href":1428,"dataGaName":646,"dataGaLocation":1429},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1120,"config":1431},{"href":972,"dataGaName":651,"dataGaLocation":1429},1786803749877]