[{"data":1,"prerenderedAt":2878},["ShallowReactive",2],{"/blog/secure-rust-development-with-gitlab":3,"navigation-en-us":2093,"banner-en-us":2518,"footer-en-us":2528,"blog-post-authors-en-us-Fernando Diaz":2773,"blog-related-posts-en-us-secure-rust-development-with-gitlab":2788,"blog-promotions-en-us":2814,"next-steps-en-us":2868},{"id":4,"title":5,"authors":6,"body":8,"category":2074,"date":2075,"description":2076,"extension":2077,"externalUrl":2078,"faq":2078,"featured":169,"heroImage":2079,"meta":2080,"navigation":169,"path":2081,"seo":2082,"slug":2085,"stem":2086,"tags":2087,"template":2091,"updatedDate":2078,"__hash__":2092},"blogPosts/en-us/blog/secure-rust-development-with-gitlab.md","Secure Rust development with GitLab",[7],"Fernando Diaz",{"type":9,"value":10,"toc":2049},"minimark",[11,22,27,67,71,74,79,96,561,564,582,586,592,836,839,859,863,883,887,893,1048,1058,1062,1065,1178,1188,1192,1203,1285,1288,1425,1455,1459,1471,1475,1481,1654,1675,1679,1682,1686,1689,1847,1858,1862,1876,1880,1887,1891,1913,1917,1921,1925,1930,1933,1937,1950,1954,1958,1971,1975,1979,1983,2045],[12,13,14,15,21],"p",{},"Rust has emerged as one of the most beloved programming languages due to its performance, memory safety, and concurrency features. As Rust adoption continues to grow, many developers are looking for robust CI/CD platforms to support their Rust projects.\nGitLab's appeal to Rust developers extends beyond simple code hosting. The platform offers robust ",[16,17,20],"a",{"href":18,"rel":19},"https://about.gitlab.com/topics/ci-cd/",[],"CI/CD"," capabilities that align perfectly with Rust's emphasis on safety, performance, and reliability. GitLab makes it easy to create repositories and use off-the-shelf Docker containers to put together custom CI jobs. Developers can easily set up automated testing, cross-platform builds, and documentation generation. The platform's integrated approach to DevSecOps resonates with Rust's philosophy of providing comprehensive tooling out of the box.",[23,24,26],"h2",{"id":25},"about-the-demo-application","About the demo application",[12,28,29,30,35,36,41,42,47,48,53,54,62,63],{},"Being interested in how mortgage rates affect monthly payments and how hard it is to to afford a house in the current times, I decided to write a ",[16,31,34],{"href":32,"rel":33},"https://gitlab.com/gitlab-da/tutorials/security-and-governance/devsecops/rust/mortgage-calculator",[],"mortgage calculator"," in Rust, which I will use as an example throughout this tutorial. Feel free to ",[16,37,40],{"href":38,"rel":39},"https://docs.gitlab.com/user/project/import/repo_by_url/",[],"import this project"," and follow along.\nThe mortgage calculator will help users calculate monthly mortgage payments, including principal, interest, property taxes, insurance, PMI, and HOA fees. It provides a modern, intuitive GUI using the ",[16,43,46],{"href":44,"rel":45},"https://www.egui.rs/",[],"egui"," framework, as well as a CLI for running it in the terminal.\n",[49,50],"img",{"alt":51,"src":52},"Mortgage calculator GUI","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314538/l5bjnzqvpoyikuyxpx2a.png","\nThis application contains a ",[16,55,58],{"href":56,"rel":57},"https://gitlab.com/gitlab-da/tutorials/security-and-governance/devsecops/rust/mortgage-calculator/-/blob/main/.gitlab-ci.yml?ref_type=heads",[],[59,60,61],"code",{},".gitlab-ci.yml"," that generates a pipeline, which will build, test, package, scan, and deploy the software. We will go over this pipeline definition in detail in the sections below.\n",[49,64],{"alt":65,"src":66},"Mortgage Calculator Pipeline","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314540/llmsfoaupedhkem0hjqp.png",[23,68,70],{"id":69},"building-and-testing-rust-applications","Building and testing Rust applications",[12,72,73],{},"GitLab's Docker-based CI/CD system excels at Rust development workflows, providing a robust foundation for compilation, testing, and code quality checks. The platform's caching mechanisms are particularly valuable for Rust projects, which can have lengthy compilation times due to the language's thorough optimization and safety checking processes.",[75,76,78],"h3",{"id":77},"building","Building",[12,80,81,82,86,87,89,90,95],{},"Rust's excellent cross-compilation capabilities combined with GitLab's flexible CI/CD system create a powerful solution for building applications across multiple platforms. This is particularly valuable for Rust applications that need to run on various operating systems and architectures without sacrificing performance or requiring platform-specific code.\n",[83,84,85],"strong",{},"Note:"," You can learn more about the ",[59,88,61],{}," by reading the ",[16,91,94],{"href":92,"rel":93},"https://docs.gitlab.com/ci/yaml/",[],"CI/CD YAML syntax reference",".",[97,98,103],"pre",{"className":99,"code":100,"language":101,"meta":102,"style":102},"language-yaml shiki shiki-themes github-light","# Cache configuration to speed up builds by reusing dependencies cache:\n  key: $CI_COMMIT_REF_SLUG                               # Use branch name as cache key\n  paths:\n    - .cargo/                                            # Cache Cargo registry and git dependencies\n    - target/                                            # Cache compiled artifacts\n\n# Base template for Rust jobs - shared configuration .rust-template:\n  image: rust:$RUST_VERSION-slim                         # Use slim Rust image for faster downloads\n  before_script:\n    # Install system dependencies required for building the Rust application\n    - apt-get update && apt-get install -y pkg-config libssl-dev libgtk-3-dev libxcb-shape0-dev libxcb-xfixes0-dev\n\n# Template for cross-compilation build jobs .build-template:\n  extends: .rust-template                                # Inherit from rust-template\n  stage: build                                           # Execute during build stage\n  script:\n    - rustup target add $TARGET                          # Add the target platform for cross-compilation\n    - cargo build --release --target $TARGET             # Build optimized release binary for target platform\n\n# Build for Linux x86_64 (primary target platform) build-linux:\n  extends: .build-template                               # Use build template configuration\n  variables:\n    TARGET: x86_64-unknown-linux-gnu                     # Linux 64-bit target\n  artifacts:\n    paths:\n      - target/$TARGET/release/mortgage-calculator       # Save the compiled binary\n    expire_in: 1 week                                    # Keep artifacts for 1 week\n  allow_failure: false                                   # This build must succeed\n\n# Build for Windows x86_64 (cross-compilation) build-windows:\n  extends: .build-template                               # Use build template configuration\n  variables:\n    TARGET: x86_64-pc-windows-gnu                        # Windows 64-bit target\n  artifacts:\n    paths:\n      - target/$TARGET/release/mortgage-calculator       # Save the compiled binary\n    expire_in: 1 week                                    # Keep artifacts for 1 week\n  allow_failure: true                                    # Allow this build to fail (cross-compilation can be tricky)\n\n# Build for macOS x86_64 (cross-compilation) build-macos:\n  extends: .build-template                               # Use build template configuration\n  variables:\n    TARGET: x86_64-apple-darwin                          # macOS 64-bit target\n  artifacts:\n    paths:\n      - target/$TARGET/release/mortgage-calculator       # Save the compiled binary\n    expire_in: 1 week                                    # Keep artifacts for 1 week\n  allow_failure: true                                    # Allow this build to fail (cross-compilation can be tricky)\n\n","yaml","",[59,104,105,114,132,141,153,164,171,177,191,199,205,213,218,224,238,252,260,271,282,287,293,306,314,328,336,344,356,370,385,390,396,407,414,427,434,441,450,461,474,479,485,496,503,516,523,530,539,550],{"__ignoreMap":102},[106,107,110],"span",{"class":108,"line":109},"line",1,[106,111,113],{"class":112},"sAwPA","# Cache configuration to speed up builds by reusing dependencies cache:\n",[106,115,117,121,125,129],{"class":108,"line":116},2,[106,118,120],{"class":119},"shJU0","  key",[106,122,124],{"class":123},"sgsFI",": ",[106,126,128],{"class":127},"sYBdl","$CI_COMMIT_REF_SLUG",[106,130,131],{"class":112},"                               # Use branch name as cache key\n",[106,133,135,138],{"class":108,"line":134},3,[106,136,137],{"class":119},"  paths",[106,139,140],{"class":123},":\n",[106,142,144,147,150],{"class":108,"line":143},4,[106,145,146],{"class":123},"    - ",[106,148,149],{"class":127},".cargo/",[106,151,152],{"class":112},"                                            # Cache Cargo registry and git dependencies\n",[106,154,156,158,161],{"class":108,"line":155},5,[106,157,146],{"class":123},[106,159,160],{"class":127},"target/",[106,162,163],{"class":112},"                                            # Cache compiled artifacts\n",[106,165,167],{"class":108,"line":166},6,[106,168,170],{"emptyLinePlaceholder":169},true,"\n",[106,172,174],{"class":108,"line":173},7,[106,175,176],{"class":112},"# Base template for Rust jobs - shared configuration .rust-template:\n",[106,178,180,183,185,188],{"class":108,"line":179},8,[106,181,182],{"class":119},"  image",[106,184,124],{"class":123},[106,186,187],{"class":127},"rust:$RUST_VERSION-slim",[106,189,190],{"class":112},"                         # Use slim Rust image for faster downloads\n",[106,192,194,197],{"class":108,"line":193},9,[106,195,196],{"class":119},"  before_script",[106,198,140],{"class":123},[106,200,202],{"class":108,"line":201},10,[106,203,204],{"class":112},"    # Install system dependencies required for building the Rust application\n",[106,206,208,210],{"class":108,"line":207},11,[106,209,146],{"class":123},[106,211,212],{"class":127},"apt-get update && apt-get install -y pkg-config libssl-dev libgtk-3-dev libxcb-shape0-dev libxcb-xfixes0-dev\n",[106,214,216],{"class":108,"line":215},12,[106,217,170],{"emptyLinePlaceholder":169},[106,219,221],{"class":108,"line":220},13,[106,222,223],{"class":112},"# Template for cross-compilation build jobs .build-template:\n",[106,225,227,230,232,235],{"class":108,"line":226},14,[106,228,229],{"class":119},"  extends",[106,231,124],{"class":123},[106,233,234],{"class":127},".rust-template",[106,236,237],{"class":112},"                                # Inherit from rust-template\n",[106,239,241,244,246,249],{"class":108,"line":240},15,[106,242,243],{"class":119},"  stage",[106,245,124],{"class":123},[106,247,248],{"class":127},"build",[106,250,251],{"class":112},"                                           # Execute during build stage\n",[106,253,255,258],{"class":108,"line":254},16,[106,256,257],{"class":119},"  script",[106,259,140],{"class":123},[106,261,263,265,268],{"class":108,"line":262},17,[106,264,146],{"class":123},[106,266,267],{"class":127},"rustup target add $TARGET",[106,269,270],{"class":112},"                          # Add the target platform for cross-compilation\n",[106,272,274,276,279],{"class":108,"line":273},18,[106,275,146],{"class":123},[106,277,278],{"class":127},"cargo build --release --target $TARGET",[106,280,281],{"class":112},"             # Build optimized release binary for target platform\n",[106,283,285],{"class":108,"line":284},19,[106,286,170],{"emptyLinePlaceholder":169},[106,288,290],{"class":108,"line":289},20,[106,291,292],{"class":112},"# Build for Linux x86_64 (primary target platform) build-linux:\n",[106,294,296,298,300,303],{"class":108,"line":295},21,[106,297,229],{"class":119},[106,299,124],{"class":123},[106,301,302],{"class":127},".build-template",[106,304,305],{"class":112},"                               # Use build template configuration\n",[106,307,309,312],{"class":108,"line":308},22,[106,310,311],{"class":119},"  variables",[106,313,140],{"class":123},[106,315,317,320,322,325],{"class":108,"line":316},23,[106,318,319],{"class":119},"    TARGET",[106,321,124],{"class":123},[106,323,324],{"class":127},"x86_64-unknown-linux-gnu",[106,326,327],{"class":112},"                     # Linux 64-bit target\n",[106,329,331,334],{"class":108,"line":330},24,[106,332,333],{"class":119},"  artifacts",[106,335,140],{"class":123},[106,337,339,342],{"class":108,"line":338},25,[106,340,341],{"class":119},"    paths",[106,343,140],{"class":123},[106,345,347,350,353],{"class":108,"line":346},26,[106,348,349],{"class":123},"      - ",[106,351,352],{"class":127},"target/$TARGET/release/mortgage-calculator",[106,354,355],{"class":112},"       # Save the compiled binary\n",[106,357,359,362,364,367],{"class":108,"line":358},27,[106,360,361],{"class":119},"    expire_in",[106,363,124],{"class":123},[106,365,366],{"class":127},"1 week",[106,368,369],{"class":112},"                                    # Keep artifacts for 1 week\n",[106,371,373,376,378,382],{"class":108,"line":372},28,[106,374,375],{"class":119},"  allow_failure",[106,377,124],{"class":123},[106,379,381],{"class":380},"sYu0t","false",[106,383,384],{"class":112},"                                   # This build must succeed\n",[106,386,388],{"class":108,"line":387},29,[106,389,170],{"emptyLinePlaceholder":169},[106,391,393],{"class":108,"line":392},30,[106,394,395],{"class":112},"# Build for Windows x86_64 (cross-compilation) build-windows:\n",[106,397,399,401,403,405],{"class":108,"line":398},31,[106,400,229],{"class":119},[106,402,124],{"class":123},[106,404,302],{"class":127},[106,406,305],{"class":112},[106,408,410,412],{"class":108,"line":409},32,[106,411,311],{"class":119},[106,413,140],{"class":123},[106,415,417,419,421,424],{"class":108,"line":416},33,[106,418,319],{"class":119},[106,420,124],{"class":123},[106,422,423],{"class":127},"x86_64-pc-windows-gnu",[106,425,426],{"class":112},"                        # Windows 64-bit target\n",[106,428,430,432],{"class":108,"line":429},34,[106,431,333],{"class":119},[106,433,140],{"class":123},[106,435,437,439],{"class":108,"line":436},35,[106,438,341],{"class":119},[106,440,140],{"class":123},[106,442,444,446,448],{"class":108,"line":443},36,[106,445,349],{"class":123},[106,447,352],{"class":127},[106,449,355],{"class":112},[106,451,453,455,457,459],{"class":108,"line":452},37,[106,454,361],{"class":119},[106,456,124],{"class":123},[106,458,366],{"class":127},[106,460,369],{"class":112},[106,462,464,466,468,471],{"class":108,"line":463},38,[106,465,375],{"class":119},[106,467,124],{"class":123},[106,469,470],{"class":380},"true",[106,472,473],{"class":112},"                                    # Allow this build to fail (cross-compilation can be tricky)\n",[106,475,477],{"class":108,"line":476},39,[106,478,170],{"emptyLinePlaceholder":169},[106,480,482],{"class":108,"line":481},40,[106,483,484],{"class":112},"# Build for macOS x86_64 (cross-compilation) build-macos:\n",[106,486,488,490,492,494],{"class":108,"line":487},41,[106,489,229],{"class":119},[106,491,124],{"class":123},[106,493,302],{"class":127},[106,495,305],{"class":112},[106,497,499,501],{"class":108,"line":498},42,[106,500,311],{"class":119},[106,502,140],{"class":123},[106,504,506,508,510,513],{"class":108,"line":505},43,[106,507,319],{"class":119},[106,509,124],{"class":123},[106,511,512],{"class":127},"x86_64-apple-darwin",[106,514,515],{"class":112},"                          # macOS 64-bit target\n",[106,517,519,521],{"class":108,"line":518},44,[106,520,333],{"class":119},[106,522,140],{"class":123},[106,524,526,528],{"class":108,"line":525},45,[106,527,341],{"class":119},[106,529,140],{"class":123},[106,531,533,535,537],{"class":108,"line":532},46,[106,534,349],{"class":123},[106,536,352],{"class":127},[106,538,355],{"class":112},[106,540,542,544,546,548],{"class":108,"line":541},47,[106,543,361],{"class":119},[106,545,124],{"class":123},[106,547,366],{"class":127},[106,549,369],{"class":112},[106,551,553,555,557,559],{"class":108,"line":552},48,[106,554,375],{"class":119},[106,556,124],{"class":123},[106,558,470],{"class":380},[106,560,473],{"class":112},[12,562,563],{},"This GitLab CI configuration defines three build jobs that cross-compile a Rust mortgage calculator application for different platforms:",[565,566,567],"ul",{},[568,569,570,573,574,577,578,581],"li",{},[59,571,572],{},"build-linux"," creates a Linux x86_64 binary (required to pass) * ",[59,575,576],{},"build-windows"," creates Windows binaries (allowed to fail) * ",[59,579,580],{},"build-macos"," creates macOS x86_64 binaries (allowed to fail)\nAll builds use shared templates for dependency caching and consistent build environments.",[75,583,585],{"id":584},"testing","Testing",[12,587,588,589,591],{},"GitLab CI/CD streamlines code testing through its integrated pipeline system that automatically triggers test suites whenever code is pushed to the repository. Developers can define multiple types of tests — unit tests, integration tests, linting, and formatting checks — all within a single ",[59,590,61],{}," configuration file, with each test running in isolated Docker containers to ensure consistent environments.",[97,593,595],{"className":99,"code":594,"language":101,"meta":102,"style":102},"# Run unit tests test:unit:\n  extends: .rust-template                                # Use Rust template configuration\n  stage: test                                            # Execute during test stage\n  script:\n    - cargo test --verbose                               # Run all unit tests with verbose output\n\n# Run integration tests using the compiled binary test:integration:\n  extends: .rust-template                                # Use Rust template configuration\n  stage: test                                            # Execute during test stage\n  script:\n    # Test the compiled binary with sample inputs and verify expected output\n    - target/x86_64-unknown-linux-gnu/release/mortgage-calculator --cli calculate --property-value 350000 --down-payment 70000 --interest-rate 5.0 | grep -q \"TOTAL MONTHLY PAYMENT\"\n  needs:\n    - build-linux                                        # Depends on Linux build job completing\n\n# Run Clippy linter for code quality checks test:clippy:\n  extends: .rust-template                                # Use Rust template configuration\n  stage: test                                            # Execute during test stage\n  script:\n    - rustup component add clippy                        # Install Clippy linter\n    - cargo clippy -- -D warnings                       # Run Clippy and treat warnings as errors\n  allow_failure: true                                    # Allow linting failures (can be improved over time)\n\n# Check code formatting test:format:\n  extends: .rust-template                                # Use Rust template configuration\n  stage: test                                            # Execute during test stage\n  script:\n    - rustup component add rustfmt                       # Install Rust formatter\n    - cargo fmt -- --check                              # Check if code is properly formatted\n  allow_failure: true                                    # Allow formatting failures (can be improved over time)\n\n",[59,596,597,602,613,625,631,641,645,650,660,670,676,681,688,695,704,708,713,723,733,739,749,759,770,774,779,789,799,805,815,825],{"__ignoreMap":102},[106,598,599],{"class":108,"line":109},[106,600,601],{"class":112},"# Run unit tests test:unit:\n",[106,603,604,606,608,610],{"class":108,"line":116},[106,605,229],{"class":119},[106,607,124],{"class":123},[106,609,234],{"class":127},[106,611,612],{"class":112},"                                # Use Rust template configuration\n",[106,614,615,617,619,622],{"class":108,"line":134},[106,616,243],{"class":119},[106,618,124],{"class":123},[106,620,621],{"class":127},"test",[106,623,624],{"class":112},"                                            # Execute during test stage\n",[106,626,627,629],{"class":108,"line":143},[106,628,257],{"class":119},[106,630,140],{"class":123},[106,632,633,635,638],{"class":108,"line":155},[106,634,146],{"class":123},[106,636,637],{"class":127},"cargo test --verbose",[106,639,640],{"class":112},"                               # Run all unit tests with verbose output\n",[106,642,643],{"class":108,"line":166},[106,644,170],{"emptyLinePlaceholder":169},[106,646,647],{"class":108,"line":173},[106,648,649],{"class":112},"# Run integration tests using the compiled binary test:integration:\n",[106,651,652,654,656,658],{"class":108,"line":179},[106,653,229],{"class":119},[106,655,124],{"class":123},[106,657,234],{"class":127},[106,659,612],{"class":112},[106,661,662,664,666,668],{"class":108,"line":193},[106,663,243],{"class":119},[106,665,124],{"class":123},[106,667,621],{"class":127},[106,669,624],{"class":112},[106,671,672,674],{"class":108,"line":201},[106,673,257],{"class":119},[106,675,140],{"class":123},[106,677,678],{"class":108,"line":207},[106,679,680],{"class":112},"    # Test the compiled binary with sample inputs and verify expected output\n",[106,682,683,685],{"class":108,"line":215},[106,684,146],{"class":123},[106,686,687],{"class":127},"target/x86_64-unknown-linux-gnu/release/mortgage-calculator --cli calculate --property-value 350000 --down-payment 70000 --interest-rate 5.0 | grep -q \"TOTAL MONTHLY PAYMENT\"\n",[106,689,690,693],{"class":108,"line":220},[106,691,692],{"class":119},"  needs",[106,694,140],{"class":123},[106,696,697,699,701],{"class":108,"line":226},[106,698,146],{"class":123},[106,700,572],{"class":127},[106,702,703],{"class":112},"                                        # Depends on Linux build job completing\n",[106,705,706],{"class":108,"line":240},[106,707,170],{"emptyLinePlaceholder":169},[106,709,710],{"class":108,"line":254},[106,711,712],{"class":112},"# Run Clippy linter for code quality checks test:clippy:\n",[106,714,715,717,719,721],{"class":108,"line":262},[106,716,229],{"class":119},[106,718,124],{"class":123},[106,720,234],{"class":127},[106,722,612],{"class":112},[106,724,725,727,729,731],{"class":108,"line":273},[106,726,243],{"class":119},[106,728,124],{"class":123},[106,730,621],{"class":127},[106,732,624],{"class":112},[106,734,735,737],{"class":108,"line":284},[106,736,257],{"class":119},[106,738,140],{"class":123},[106,740,741,743,746],{"class":108,"line":289},[106,742,146],{"class":123},[106,744,745],{"class":127},"rustup component add clippy",[106,747,748],{"class":112},"                        # Install Clippy linter\n",[106,750,751,753,756],{"class":108,"line":295},[106,752,146],{"class":123},[106,754,755],{"class":127},"cargo clippy -- -D warnings",[106,757,758],{"class":112},"                       # Run Clippy and treat warnings as errors\n",[106,760,761,763,765,767],{"class":108,"line":308},[106,762,375],{"class":119},[106,764,124],{"class":123},[106,766,470],{"class":380},[106,768,769],{"class":112},"                                    # Allow linting failures (can be improved over time)\n",[106,771,772],{"class":108,"line":316},[106,773,170],{"emptyLinePlaceholder":169},[106,775,776],{"class":108,"line":330},[106,777,778],{"class":112},"# Check code formatting test:format:\n",[106,780,781,783,785,787],{"class":108,"line":338},[106,782,229],{"class":119},[106,784,124],{"class":123},[106,786,234],{"class":127},[106,788,612],{"class":112},[106,790,791,793,795,797],{"class":108,"line":346},[106,792,243],{"class":119},[106,794,124],{"class":123},[106,796,621],{"class":127},[106,798,624],{"class":112},[106,800,801,803],{"class":108,"line":358},[106,802,257],{"class":119},[106,804,140],{"class":123},[106,806,807,809,812],{"class":108,"line":372},[106,808,146],{"class":123},[106,810,811],{"class":127},"rustup component add rustfmt",[106,813,814],{"class":112},"                       # Install Rust formatter\n",[106,816,817,819,822],{"class":108,"line":387},[106,818,146],{"class":123},[106,820,821],{"class":127},"cargo fmt -- --check",[106,823,824],{"class":112},"                              # Check if code is properly formatted\n",[106,826,827,829,831,833],{"class":108,"line":392},[106,828,375],{"class":119},[106,830,124],{"class":123},[106,832,470],{"class":380},[106,834,835],{"class":112},"                                    # Allow formatting failures (can be improved over time)\n",[12,837,838],{},"This GitLab CI configuration creates four test jobs that validate a Rust mortgage calculator application:",[565,840,841],{},[568,842,843,846,847,850,851,854,855,858],{},[59,844,845],{},"test:unit"," runs unit tests * ",[59,848,849],{},"test:integration"," executes the compiled Linux binary with sample inputs to verify functionality * ",[59,852,853],{},"test:clippy"," performs code quality linting (allowed to fail) * ",[59,856,857],{},"test:format"," checks code formatting compliance (allowed to fail)",[23,860,862],{"id":861},"package-and-container-registries","Package and Container Registries",[12,864,865,866,871,872,877,878,95],{},"GitLab's ",[16,867,870],{"href":868,"rel":869},"https://docs.gitlab.com/user/packages/package_registry/",[],"Package Registry"," provides a secure solution to the common challenge of sharing internal libraries and proprietary code within organizations. This capability is essential for enterprises and teams that need to maintain artifacts while leveraging the broader Rust ecosystem.\nThe registry supports ",[16,873,876],{"href":874,"rel":875},"https://docs.gitlab.com/user/packages/generic_packages/",[],"generic artifacts"," with fine-grained access controls that align with GitLab's project permissions. This means teams can share libraries securely across projects while maintaining intellectual property protection and compliance requirements.\nAdditonally, we can containerize our application and store the container images in GitLab's built-in ",[16,879,882],{"href":880,"rel":881},"https://docs.gitlab.com/user/packages/container_registry/",[],"Container Registry",[75,884,886],{"id":885},"publishing-to-gitlab-package-registry","Publishing to GitLab Package Registry",[12,888,889,890,892],{},"This section of our ",[59,891,61],{}," demonstrates how to package and publish Rust applications as tar archives to GitLab's generic package registry using CI/CD automation.",[97,894,896],{"className":99,"code":895,"language":101,"meta":102,"style":102},"# Package application as tar archive package:tar:\n  image: alpine/curl:8.12.1                             # Lightweight image with curl for uploading\n  stage: package                                         # Execute during package stage\n  variables:\n    PACKAGE_NAME: mortgage-calculator.tar.gz             # Name of the archive file\n  script:\n    # Create tar archive of the Linux binary\n    - tar -czvf $PACKAGE_NAME target/x86_64-unknown-linux-gnu/release/mortgage-calculator\n    # Upload archive to GitLab Package Registry using API\n    - |\n      curl -v --location --header \"JOB-TOKEN: $CI_JOB_TOKEN\" \\\n      --upload-file $PACKAGE_NAME \\\n      \"$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/generic/tar/$CI_COMMIT_BRANCH/$PACKAGE_NAME\"\n  artifacts:\n    paths:\n      - target/x86_64-unknown-linux-gnu/release/mortgage-calculator  # Save binary\n      - mortgage-calculator.tar.gz                      # Save archive\n    expire_in: 1 week                                    # Keep artifacts for 1 week\n  needs:\n    - build-linux                                        # Depends on Linux build completing\n\n",[59,897,898,903,915,927,933,946,952,957,964,969,977,982,987,992,998,1004,1014,1023,1033,1039],{"__ignoreMap":102},[106,899,900],{"class":108,"line":109},[106,901,902],{"class":112},"# Package application as tar archive package:tar:\n",[106,904,905,907,909,912],{"class":108,"line":116},[106,906,182],{"class":119},[106,908,124],{"class":123},[106,910,911],{"class":127},"alpine/curl:8.12.1",[106,913,914],{"class":112},"                             # Lightweight image with curl for uploading\n",[106,916,917,919,921,924],{"class":108,"line":134},[106,918,243],{"class":119},[106,920,124],{"class":123},[106,922,923],{"class":127},"package",[106,925,926],{"class":112},"                                         # Execute during package stage\n",[106,928,929,931],{"class":108,"line":143},[106,930,311],{"class":119},[106,932,140],{"class":123},[106,934,935,938,940,943],{"class":108,"line":155},[106,936,937],{"class":119},"    PACKAGE_NAME",[106,939,124],{"class":123},[106,941,942],{"class":127},"mortgage-calculator.tar.gz",[106,944,945],{"class":112},"             # Name of the archive file\n",[106,947,948,950],{"class":108,"line":166},[106,949,257],{"class":119},[106,951,140],{"class":123},[106,953,954],{"class":108,"line":173},[106,955,956],{"class":112},"    # Create tar archive of the Linux binary\n",[106,958,959,961],{"class":108,"line":179},[106,960,146],{"class":123},[106,962,963],{"class":127},"tar -czvf $PACKAGE_NAME target/x86_64-unknown-linux-gnu/release/mortgage-calculator\n",[106,965,966],{"class":108,"line":193},[106,967,968],{"class":112},"    # Upload archive to GitLab Package Registry using API\n",[106,970,971,973],{"class":108,"line":201},[106,972,146],{"class":123},[106,974,976],{"class":975},"sD7c4","|\n",[106,978,979],{"class":108,"line":207},[106,980,981],{"class":127},"      curl -v --location --header \"JOB-TOKEN: $CI_JOB_TOKEN\" \\\n",[106,983,984],{"class":108,"line":215},[106,985,986],{"class":127},"      --upload-file $PACKAGE_NAME \\\n",[106,988,989],{"class":108,"line":220},[106,990,991],{"class":127},"      \"$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/generic/tar/$CI_COMMIT_BRANCH/$PACKAGE_NAME\"\n",[106,993,994,996],{"class":108,"line":226},[106,995,333],{"class":119},[106,997,140],{"class":123},[106,999,1000,1002],{"class":108,"line":240},[106,1001,341],{"class":119},[106,1003,140],{"class":123},[106,1005,1006,1008,1011],{"class":108,"line":254},[106,1007,349],{"class":123},[106,1009,1010],{"class":127},"target/x86_64-unknown-linux-gnu/release/mortgage-calculator",[106,1012,1013],{"class":112},"  # Save binary\n",[106,1015,1016,1018,1020],{"class":108,"line":262},[106,1017,349],{"class":123},[106,1019,942],{"class":127},[106,1021,1022],{"class":112},"                      # Save archive\n",[106,1024,1025,1027,1029,1031],{"class":108,"line":273},[106,1026,361],{"class":119},[106,1028,124],{"class":123},[106,1030,366],{"class":127},[106,1032,369],{"class":112},[106,1034,1035,1037],{"class":108,"line":284},[106,1036,692],{"class":119},[106,1038,140],{"class":123},[106,1040,1041,1043,1045],{"class":108,"line":289},[106,1042,146],{"class":123},[106,1044,572],{"class":127},[106,1046,1047],{"class":112},"                                        # Depends on Linux build completing\n",[12,1049,1050,1051,1054,1055],{},"This GitLab CI configuration defines one packaging job ",[59,1052,1053],{},"package:tar"," that creates a compressed tar archive of the Linux mortgage calculator binary and uploads it to GitLab's Package Registry, while also saving both the binary and archive as pipeline artifacts.\n",[49,1056],{"alt":870,"src":1057},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314541/uqnejcipnge3r1dngotm.png",[75,1059,1061],{"id":1060},"publishing-to-gitlab-container-registry","Publishing to GitLab Container Registry",[12,1063,1064],{},"The below shows the process of building Dockerfiles and publishing Docker images to GitLab's Container Registry with proper tagging and authentication.",[97,1066,1068],{"className":99,"code":1067,"language":101,"meta":102,"style":102},"# Package application as Docker image package:docker:\n  image: docker:24.0                                     # Use Docker image for building containers\n  stage: package                                         # Execute during package stage\n  services:\n    - docker:24.0-dind                                   # Docker-in-Docker service for building images\n  before_script:\n    # Login to GitLab Container Registry\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n  script:\n    - docker build -t $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG .  # Build Docker image with commit SHA tag\n    - docker tag $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG $DOCKER_IMAGE_NAME:latest  # Also tag as latest\n    - docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG  # Push tagged image to registry\n    - docker push $DOCKER_IMAGE_NAME:latest             # Push latest image to registry\n\n",[59,1069,1070,1075,1087,1097,1104,1114,1120,1125,1132,1138,1148,1158,1168],{"__ignoreMap":102},[106,1071,1072],{"class":108,"line":109},[106,1073,1074],{"class":112},"# Package application as Docker image package:docker:\n",[106,1076,1077,1079,1081,1084],{"class":108,"line":116},[106,1078,182],{"class":119},[106,1080,124],{"class":123},[106,1082,1083],{"class":127},"docker:24.0",[106,1085,1086],{"class":112},"                                     # Use Docker image for building containers\n",[106,1088,1089,1091,1093,1095],{"class":108,"line":134},[106,1090,243],{"class":119},[106,1092,124],{"class":123},[106,1094,923],{"class":127},[106,1096,926],{"class":112},[106,1098,1099,1102],{"class":108,"line":143},[106,1100,1101],{"class":119},"  services",[106,1103,140],{"class":123},[106,1105,1106,1108,1111],{"class":108,"line":155},[106,1107,146],{"class":123},[106,1109,1110],{"class":127},"docker:24.0-dind",[106,1112,1113],{"class":112},"                                   # Docker-in-Docker service for building images\n",[106,1115,1116,1118],{"class":108,"line":166},[106,1117,196],{"class":119},[106,1119,140],{"class":123},[106,1121,1122],{"class":108,"line":173},[106,1123,1124],{"class":112},"    # Login to GitLab Container Registry\n",[106,1126,1127,1129],{"class":108,"line":179},[106,1128,146],{"class":123},[106,1130,1131],{"class":127},"docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n",[106,1133,1134,1136],{"class":108,"line":193},[106,1135,257],{"class":119},[106,1137,140],{"class":123},[106,1139,1140,1142,1145],{"class":108,"line":201},[106,1141,146],{"class":123},[106,1143,1144],{"class":127},"docker build -t $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG .",[106,1146,1147],{"class":112},"  # Build Docker image with commit SHA tag\n",[106,1149,1150,1152,1155],{"class":108,"line":207},[106,1151,146],{"class":123},[106,1153,1154],{"class":127},"docker tag $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG $DOCKER_IMAGE_NAME:latest",[106,1156,1157],{"class":112},"  # Also tag as latest\n",[106,1159,1160,1162,1165],{"class":108,"line":215},[106,1161,146],{"class":123},[106,1163,1164],{"class":127},"docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG",[106,1166,1167],{"class":112},"  # Push tagged image to registry\n",[106,1169,1170,1172,1175],{"class":108,"line":220},[106,1171,146],{"class":123},[106,1173,1174],{"class":127},"docker push $DOCKER_IMAGE_NAME:latest",[106,1176,1177],{"class":112},"             # Push latest image to registry\n",[12,1179,1180,1181,1184,1185],{},"This GitLab CI configuration defines one Docker packaging job ",[59,1182,1183],{},"package:docker"," that builds a Docker image of the mortgage calculator application, tags it with both the commit SHA and \"latest,\" and then pushes both tagged versions to  GitLab's Container Registry.\n",[49,1186],{"alt":882,"src":1187},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314537/nlodhvdnpqccf0cryfqu.png",[23,1189,1191],{"id":1190},"security-scanning","Security scanning",[12,1193,1194,1195,1197,1198,95],{},"GitLab security scanning provides comprehensive protection that goes beyond Rust's built-in memory safety guarantees. While Rust prevents many common security vulnerabilities at compile time, applications still need protection against dependency vulnerabilities, unsafe code blocks, and logical security issues.\nThe platform's Static Application Security Testing (SAST) integrates seamlessly with Rust's toolchain, providing automated security analysis as part of the CI/CD pipeline This proactive approach catches security issues before they reach production, supporting both compliance requirements and secure development practices.\nGitLab's comprehensive security features including SAST, dependency scanning, secret detection and more can easily be implemented via templates, as seen below. ",[83,1196,85],{}," Additional configuration is required to ",[16,1199,1202],{"href":1200,"rel":1201},"https://docs.gitlab.com/user/application_security/sast/#scan-a-rust-application",[],"enable SAST for Rust",[97,1204,1206],{"className":99,"code":1205,"language":101,"meta":102,"style":102},"# Include GitLab's security scanning templates for DevSecOps include:\n  - template: Jobs/SAST.gitlab-ci.yml                    # Static Application Security Testing\n  - template: Jobs/Dependency-Scanning.latest.gitlab-ci.yml  # Scan dependencies for vulnerabilities\n  - template: Jobs/Container-Scanning.gitlab-ci.yml      # Scan Docker containers for vulnerabilities\n  - template: Jobs/SAST-IaC.gitlab-ci.yml               # Infrastructure as Code security scanning\n  - template: Jobs/Secret-Detection.gitlab-ci.yml        # Detect secrets in source code\n\n",[59,1207,1208,1213,1229,1243,1257,1271],{"__ignoreMap":102},[106,1209,1210],{"class":108,"line":109},[106,1211,1212],{"class":112},"# Include GitLab's security scanning templates for DevSecOps include:\n",[106,1214,1215,1218,1221,1223,1226],{"class":108,"line":116},[106,1216,1217],{"class":123},"  - ",[106,1219,1220],{"class":119},"template",[106,1222,124],{"class":123},[106,1224,1225],{"class":127},"Jobs/SAST.gitlab-ci.yml",[106,1227,1228],{"class":112},"                    # Static Application Security Testing\n",[106,1230,1231,1233,1235,1237,1240],{"class":108,"line":134},[106,1232,1217],{"class":123},[106,1234,1220],{"class":119},[106,1236,124],{"class":123},[106,1238,1239],{"class":127},"Jobs/Dependency-Scanning.latest.gitlab-ci.yml",[106,1241,1242],{"class":112},"  # Scan dependencies for vulnerabilities\n",[106,1244,1245,1247,1249,1251,1254],{"class":108,"line":143},[106,1246,1217],{"class":123},[106,1248,1220],{"class":119},[106,1250,124],{"class":123},[106,1252,1253],{"class":127},"Jobs/Container-Scanning.gitlab-ci.yml",[106,1255,1256],{"class":112},"      # Scan Docker containers for vulnerabilities\n",[106,1258,1259,1261,1263,1265,1268],{"class":108,"line":155},[106,1260,1217],{"class":123},[106,1262,1220],{"class":119},[106,1264,124],{"class":123},[106,1266,1267],{"class":127},"Jobs/SAST-IaC.gitlab-ci.yml",[106,1269,1270],{"class":112},"               # Infrastructure as Code security scanning\n",[106,1272,1273,1275,1277,1279,1282],{"class":108,"line":166},[106,1274,1217],{"class":123},[106,1276,1220],{"class":119},[106,1278,124],{"class":123},[106,1280,1281],{"class":127},"Jobs/Secret-Detection.gitlab-ci.yml",[106,1283,1284],{"class":112},"        # Detect secrets in source code\n",[12,1286,1287],{},"Security scanners can be configured similar to how you would configure any GitLab job:",[97,1289,1291],{"className":99,"code":1290,"language":101,"meta":102,"style":102},"# Configure Semgrep SAST scanning for Rust files semgrep-sast:\n  rules:\n    - if: $CI_COMMIT_BRANCH                              # Run on any branch\n      exists:\n        - \"**/*.rs\"                                      # Only if Rust files exist\n  variables:\n    SAST_EXCLUDED_PATHS: \".cargo/**\"                     # Exclude Cargo cache from scanning\n\n# Scan Docker container for security vulnerabilities container_scanning:\n  stage: container-security                              # Execute during container-security stage\n  variables:\n    CS_IMAGE: $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG      # Image to scan\n    CS_DOCKERFILE_PATH: Dockerfile                       # Path to Dockerfile for context\n  needs:\n    - package:docker                                     # Depends on Docker image being built\n\n",[59,1292,1293,1298,1305,1320,1327,1338,1344,1357,1361,1366,1378,1384,1397,1410,1416],{"__ignoreMap":102},[106,1294,1295],{"class":108,"line":109},[106,1296,1297],{"class":112},"# Configure Semgrep SAST scanning for Rust files semgrep-sast:\n",[106,1299,1300,1303],{"class":108,"line":116},[106,1301,1302],{"class":119},"  rules",[106,1304,140],{"class":123},[106,1306,1307,1309,1312,1314,1317],{"class":108,"line":134},[106,1308,146],{"class":123},[106,1310,1311],{"class":119},"if",[106,1313,124],{"class":123},[106,1315,1316],{"class":127},"$CI_COMMIT_BRANCH",[106,1318,1319],{"class":112},"                              # Run on any branch\n",[106,1321,1322,1325],{"class":108,"line":143},[106,1323,1324],{"class":119},"      exists",[106,1326,140],{"class":123},[106,1328,1329,1332,1335],{"class":108,"line":155},[106,1330,1331],{"class":123},"        - ",[106,1333,1334],{"class":127},"\"**/*.rs\"",[106,1336,1337],{"class":112},"                                      # Only if Rust files exist\n",[106,1339,1340,1342],{"class":108,"line":166},[106,1341,311],{"class":119},[106,1343,140],{"class":123},[106,1345,1346,1349,1351,1354],{"class":108,"line":173},[106,1347,1348],{"class":119},"    SAST_EXCLUDED_PATHS",[106,1350,124],{"class":123},[106,1352,1353],{"class":127},"\".cargo/**\"",[106,1355,1356],{"class":112},"                     # Exclude Cargo cache from scanning\n",[106,1358,1359],{"class":108,"line":179},[106,1360,170],{"emptyLinePlaceholder":169},[106,1362,1363],{"class":108,"line":193},[106,1364,1365],{"class":112},"# Scan Docker container for security vulnerabilities container_scanning:\n",[106,1367,1368,1370,1372,1375],{"class":108,"line":201},[106,1369,243],{"class":119},[106,1371,124],{"class":123},[106,1373,1374],{"class":127},"container-security",[106,1376,1377],{"class":112},"                              # Execute during container-security stage\n",[106,1379,1380,1382],{"class":108,"line":207},[106,1381,311],{"class":119},[106,1383,140],{"class":123},[106,1385,1386,1389,1391,1394],{"class":108,"line":215},[106,1387,1388],{"class":119},"    CS_IMAGE",[106,1390,124],{"class":123},[106,1392,1393],{"class":127},"$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG",[106,1395,1396],{"class":112},"      # Image to scan\n",[106,1398,1399,1402,1404,1407],{"class":108,"line":220},[106,1400,1401],{"class":119},"    CS_DOCKERFILE_PATH",[106,1403,124],{"class":123},[106,1405,1406],{"class":127},"Dockerfile",[106,1408,1409],{"class":112},"                       # Path to Dockerfile for context\n",[106,1411,1412,1414],{"class":108,"line":226},[106,1413,692],{"class":119},[106,1415,140],{"class":123},[106,1417,1418,1420,1422],{"class":108,"line":240},[106,1419,146],{"class":123},[106,1421,1183],{"class":127},[106,1423,1424],{"class":112},"                                     # Depends on Docker image being built\n",[12,1426,1427,1428,1432,1433,1438,1439,1441,1442,1446,1447,140,1452],{},"When vulnerabilites are detected in a merge request (MR), you can see all the vulnerabilites detected and use the provided information to either resolve or dismiss vulnerabilities.\n",[49,1429],{"alt":1430,"src":1431},"Vulnerability MR view","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314544/gcicke3ltvbcv57mr8zr.png","\nYou also can add ",[16,1434,1437],{"href":1435,"rel":1436},"https://docs.gitlab.com/user/application_security/policies/",[],"Security Policies"," to require approval before vulnerable code can be merged, or to force scanners to run regardless of what is in the ",[59,1440,61],{},".\n",[49,1443],{"alt":1444,"src":1445},"Merge Request Approval Policy","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314538/c95nwocol03lonrr6r4n.png","\nYou can triage all the vulnerabilities found in your default branch by using the ",[16,1448,1451],{"href":1449,"rel":1450},"https://docs.gitlab.com/user/application_security/vulnerability_report/",[],"Vulnerability Report",[49,1453],{"alt":1451,"src":1454},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314544/b0nctigbv1ddpzizkp9x.png",[23,1456,1458],{"id":1457},"documentation-with-gitlab-pages","Documentation with GitLab Pages",[12,1460,1461,1466,1467,1470],{},[16,1462,1465],{"href":1463,"rel":1464},"https://docs.gitlab.com/user/project/pages/",[],"GitLab Pages"," provides an excellent platform for hosting Rust documentation, integrating seamlessly with Cargo's built-in documentation generation. This creates a powerful workflow where API documentation, project guides, and examples are automatically generated and deployed with every code change.\nThe combination of ",[59,1468,1469],{},"cargo doc"," and GitLab Pages enables teams to maintain up-to-date documentation without manual intervention, ensuring that documentation stays synchronized with code changes. This is particularly valuable for Rust projects where comprehensive documentation is essential to understand complex APIs and safety contracts.",[75,1472,1474],{"id":1473},"automated-documentation-deployment","Automated documentation deployment",[12,1476,1477,1478,1480],{},"The following code shows the CI/CD configuration for automatically generating and deploying Rust documentation using ",[59,1479,1469],{}," and GitLab Pages.",[97,1482,1484],{"className":99,"code":1483,"language":101,"meta":102,"style":102},"# Generate and publish documentation using GitLab Pages build-documentation:\n  extends: .rust-template                                # Use Rust template configuration\n  stage: build                                           # Execute during build stage\n  variables:\n    GIT_SUBMODULE_STRATEGY: recursive                    # Clone submodules recursively if needed\n  pages: true                                            # Enable GitLab Pages deployment\n  script:\n    - cargo doc --no-deps                                # Generate documentation without dependencies\n    - mv target/doc public                               # Move docs to public directory for Pages\n  artifacts:\n    paths:\n      - public                                           # GitLab Pages serves from public directory\n  rules:\n    - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH     # Only run on default branch (main/master)\n  environment:\n    name: documentation                                  # Environment name for tracking\n    url: $CI_PAGES_URL/mortgage_calculator/index.html   # Documentation URL\n  allow_failure: true                                    # Allow documentation build to fail\n\n",[59,1485,1486,1491,1501,1511,1517,1530,1542,1548,1558,1568,1574,1580,1590,1596,1610,1617,1630,1643],{"__ignoreMap":102},[106,1487,1488],{"class":108,"line":109},[106,1489,1490],{"class":112},"# Generate and publish documentation using GitLab Pages build-documentation:\n",[106,1492,1493,1495,1497,1499],{"class":108,"line":116},[106,1494,229],{"class":119},[106,1496,124],{"class":123},[106,1498,234],{"class":127},[106,1500,612],{"class":112},[106,1502,1503,1505,1507,1509],{"class":108,"line":134},[106,1504,243],{"class":119},[106,1506,124],{"class":123},[106,1508,248],{"class":127},[106,1510,251],{"class":112},[106,1512,1513,1515],{"class":108,"line":143},[106,1514,311],{"class":119},[106,1516,140],{"class":123},[106,1518,1519,1522,1524,1527],{"class":108,"line":155},[106,1520,1521],{"class":119},"    GIT_SUBMODULE_STRATEGY",[106,1523,124],{"class":123},[106,1525,1526],{"class":127},"recursive",[106,1528,1529],{"class":112},"                    # Clone submodules recursively if needed\n",[106,1531,1532,1535,1537,1539],{"class":108,"line":166},[106,1533,1534],{"class":119},"  pages",[106,1536,124],{"class":123},[106,1538,470],{"class":380},[106,1540,1541],{"class":112},"                                            # Enable GitLab Pages deployment\n",[106,1543,1544,1546],{"class":108,"line":173},[106,1545,257],{"class":119},[106,1547,140],{"class":123},[106,1549,1550,1552,1555],{"class":108,"line":179},[106,1551,146],{"class":123},[106,1553,1554],{"class":127},"cargo doc --no-deps",[106,1556,1557],{"class":112},"                                # Generate documentation without dependencies\n",[106,1559,1560,1562,1565],{"class":108,"line":193},[106,1561,146],{"class":123},[106,1563,1564],{"class":127},"mv target/doc public",[106,1566,1567],{"class":112},"                               # Move docs to public directory for Pages\n",[106,1569,1570,1572],{"class":108,"line":201},[106,1571,333],{"class":119},[106,1573,140],{"class":123},[106,1575,1576,1578],{"class":108,"line":207},[106,1577,341],{"class":119},[106,1579,140],{"class":123},[106,1581,1582,1584,1587],{"class":108,"line":215},[106,1583,349],{"class":123},[106,1585,1586],{"class":127},"public",[106,1588,1589],{"class":112},"                                           # GitLab Pages serves from public directory\n",[106,1591,1592,1594],{"class":108,"line":220},[106,1593,1302],{"class":119},[106,1595,140],{"class":123},[106,1597,1598,1600,1602,1604,1607],{"class":108,"line":226},[106,1599,146],{"class":123},[106,1601,1311],{"class":119},[106,1603,124],{"class":123},[106,1605,1606],{"class":127},"$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH",[106,1608,1609],{"class":112},"     # Only run on default branch (main/master)\n",[106,1611,1612,1615],{"class":108,"line":240},[106,1613,1614],{"class":119},"  environment",[106,1616,140],{"class":123},[106,1618,1619,1622,1624,1627],{"class":108,"line":254},[106,1620,1621],{"class":119},"    name",[106,1623,124],{"class":123},[106,1625,1626],{"class":127},"documentation",[106,1628,1629],{"class":112},"                                  # Environment name for tracking\n",[106,1631,1632,1635,1637,1640],{"class":108,"line":262},[106,1633,1634],{"class":119},"    url",[106,1636,124],{"class":123},[106,1638,1639],{"class":127},"$CI_PAGES_URL/mortgage_calculator/index.html",[106,1641,1642],{"class":112},"   # Documentation URL\n",[106,1644,1645,1647,1649,1651],{"class":108,"line":273},[106,1646,375],{"class":119},[106,1648,124],{"class":123},[106,1650,470],{"class":380},[106,1652,1653],{"class":112},"                                    # Allow documentation build to fail\n",[12,1655,1656,1657,1662,1663,1667,1668,1670,1671],{},"Once the job is complete, you can see the deployed documentation by visiting the ",[16,1658,1661],{"href":1659,"rel":1660},"https://docs.gitlab.com/ci/environments/",[],"GitLab Environment"," it has been deployed to.\n",[49,1664],{"alt":1665,"src":1666},"Pages environment","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314541/aofa6wwjugeyeshuwg9r.png","\nThis allows you to manage multiple versions of the documentation in different envrionments. The documentation will be deployed consistent with the ",[59,1669,1469],{}," output:\n",[49,1672],{"alt":1673,"src":1674},"Pages build","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314541/go0tmljjzoxq5bujsdbv.png",[23,1676,1678],{"id":1677},"deploy-anywhere","Deploy anywhere",[12,1680,1681],{},"One of GitLab's greatest strengths is its infrastructure-agnostic approach to deployment. Whether your organization runs on traditional on-premises servers, modern cloud platforms, hybrid environments, or edge computing infrastructure, GitLab's CI/CD system can deploy Rust applications seamlessly across any target environment.\nGitLab's deployment flexibility stems from its container-first approach and extensive integration ecosystem. The platform supports deployment to virtually any infrastructure that can run containers, virtual machines, or bare-metal applications. This versatility is particularly valuable for Rust applications, which often need to run in diverse environments ranging from resource-constrained embedded systems to high-performance cloud clusters.",[75,1683,1685],{"id":1684},"kubernetes-deployment","Kubernetes deployment",[12,1687,1688],{},"GitLab simplifies Kubernetes deployments by providing built-in cluster integration and pre-configured Docker images that include essential tools like Helm and kubectl, eliminating the need for developers to set up complex deployment environments.",[97,1690,1692],{"className":99,"code":1691,"language":101,"meta":102,"style":102},"# Deploy application to Kubernetes cluster deploy:kubernetes:\n  stage: deploy                                          # Execute during deploy stage\n  image: registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image:helm-3.10.0-kube-1.24.6-alpine-3.15  # Image with Helm and kubectl\n  variables:\n    HELM_HOST: \"localhost:44134\"                         # Helm host configuration\n    HELM_DEPLOY_NAME: mortgage-calc-$CI_COMMIT_REF_NAME  # Deployment name based on branch\n    HELM_DEPLOY_NAMESPACE: calc-app                      # Kubernetes namespace for deployment\n    KUBE_CONTEXT: $CI_PROJECT_PATH:rust-mortgage-calculator  # Kubernetes context to use\n  script:\n    - kubectl config use-context $KUBE_CONTEXT          # Set the kubectl context\n    # Deploy using Helm with custom values and Docker image\n    - helm upgrade --install $HELM_DEPLOY_NAME chart -f chart/values.yaml\n      --namespace $HELM_DEPLOY_NAMESPACE\n      --create-namespace\n      --set image=$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG\n      --set calc.name=$HELM_DEPLOY_NAME \n  needs:\n    - package:docker                                     # Depends on Docker image being available\n\n",[59,1693,1694,1699,1711,1723,1729,1742,1755,1768,1781,1787,1797,1802,1809,1814,1819,1824,1832,1838],{"__ignoreMap":102},[106,1695,1696],{"class":108,"line":109},[106,1697,1698],{"class":112},"# Deploy application to Kubernetes cluster deploy:kubernetes:\n",[106,1700,1701,1703,1705,1708],{"class":108,"line":116},[106,1702,243],{"class":119},[106,1704,124],{"class":123},[106,1706,1707],{"class":127},"deploy",[106,1709,1710],{"class":112},"                                          # Execute during deploy stage\n",[106,1712,1713,1715,1717,1720],{"class":108,"line":134},[106,1714,182],{"class":119},[106,1716,124],{"class":123},[106,1718,1719],{"class":127},"registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image:helm-3.10.0-kube-1.24.6-alpine-3.15",[106,1721,1722],{"class":112},"  # Image with Helm and kubectl\n",[106,1724,1725,1727],{"class":108,"line":143},[106,1726,311],{"class":119},[106,1728,140],{"class":123},[106,1730,1731,1734,1736,1739],{"class":108,"line":155},[106,1732,1733],{"class":119},"    HELM_HOST",[106,1735,124],{"class":123},[106,1737,1738],{"class":127},"\"localhost:44134\"",[106,1740,1741],{"class":112},"                         # Helm host configuration\n",[106,1743,1744,1747,1749,1752],{"class":108,"line":166},[106,1745,1746],{"class":119},"    HELM_DEPLOY_NAME",[106,1748,124],{"class":123},[106,1750,1751],{"class":127},"mortgage-calc-$CI_COMMIT_REF_NAME",[106,1753,1754],{"class":112},"  # Deployment name based on branch\n",[106,1756,1757,1760,1762,1765],{"class":108,"line":173},[106,1758,1759],{"class":119},"    HELM_DEPLOY_NAMESPACE",[106,1761,124],{"class":123},[106,1763,1764],{"class":127},"calc-app",[106,1766,1767],{"class":112},"                      # Kubernetes namespace for deployment\n",[106,1769,1770,1773,1775,1778],{"class":108,"line":179},[106,1771,1772],{"class":119},"    KUBE_CONTEXT",[106,1774,124],{"class":123},[106,1776,1777],{"class":127},"$CI_PROJECT_PATH:rust-mortgage-calculator",[106,1779,1780],{"class":112},"  # Kubernetes context to use\n",[106,1782,1783,1785],{"class":108,"line":193},[106,1784,257],{"class":119},[106,1786,140],{"class":123},[106,1788,1789,1791,1794],{"class":108,"line":201},[106,1790,146],{"class":123},[106,1792,1793],{"class":127},"kubectl config use-context $KUBE_CONTEXT",[106,1795,1796],{"class":112},"          # Set the kubectl context\n",[106,1798,1799],{"class":108,"line":207},[106,1800,1801],{"class":112},"    # Deploy using Helm with custom values and Docker image\n",[106,1803,1804,1806],{"class":108,"line":215},[106,1805,146],{"class":123},[106,1807,1808],{"class":127},"helm upgrade --install $HELM_DEPLOY_NAME chart -f chart/values.yaml\n",[106,1810,1811],{"class":108,"line":220},[106,1812,1813],{"class":127},"      --namespace $HELM_DEPLOY_NAMESPACE\n",[106,1815,1816],{"class":108,"line":226},[106,1817,1818],{"class":127},"      --create-namespace\n",[106,1820,1821],{"class":108,"line":240},[106,1822,1823],{"class":127},"      --set image=$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG\n",[106,1825,1826,1829],{"class":108,"line":254},[106,1827,1828],{"class":127},"      --set calc.name=$HELM_DEPLOY_NAME",[106,1830,1831],{"class":123}," \n",[106,1833,1834,1836],{"class":108,"line":262},[106,1835,692],{"class":119},[106,1837,140],{"class":123},[106,1839,1840,1842,1844],{"class":108,"line":273},[106,1841,146],{"class":123},[106,1843,1183],{"class":127},[106,1845,1846],{"class":112},"                                     # Depends on Docker image being available\n",[12,1848,1849,1850,1853,1854],{},"This GitLab CI configuration defines one deployment job ",[59,1851,1852],{},"deploy:kubernetes"," that uses Helm to deploy the mortgage calculator application to a Kubernetes cluster, creating or upgrading the deployment in a dedicated namespace while using the Docker image built in the previous packaging stage.\n",[49,1855],{"alt":1856,"src":1857},"Kubernetes output","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314538/bgmbh4qyfxcnnlqvsitc.png",[23,1859,1861],{"id":1860},"gitlab-duo-ai-features","GitLab Duo AI features",[12,1863,1864,1869,1870,1875],{},[16,1865,1868],{"href":1866,"rel":1867},"https://about.gitlab.com/gitlab-duo-agent-platform/",[],"GitLab Duo"," AI features provide significant advantages for Rust development by offering intelligent code suggestions and explanations specifically tailored to the language's unique syntax and patterns.\nThe GitLab platform supports Rust as one of its ",[16,1871,1874],{"href":1872,"rel":1873},"https://docs.gitlab.com/user/project/repository/code_suggestions/supported_extensions/#supported-languages-by-ide",[],"directly-supported languages"," for every IDE, ensuring high-quality code completion and generation that understands Rust's ownership model, memory safety principles, and idiomatic patterns.",[75,1877,1879],{"id":1878},"gitlab-duo-code-suggestions","GitLab Duo Code Suggestions",[12,1881,1882,1883],{},"GitLab Duo's ability to provide contextual code suggestions while typing helps developers navigate Rust's sometimes complex syntax more efficiently, reducing the learning curve for newcomers and accelerating productivity for experienced developers.\n",[49,1884],{"alt":1885,"src":1886},"Code Suggestions","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314538/uvy6hmzvyd0mnqeic9tq.png",[75,1888,1890],{"id":1889},"gitlab-duo-chat","GitLab Duo Chat",[12,1892,1893,1897,1898,1901,1902,1907,1908,1912],{},[16,1894,1890],{"href":1895,"rel":1896},"https://about.gitlab.com/blog/gitlab-duo-chat-gets-agentic-ai-makeover/",[]," complements the code suggestions by offering conversational assistance for explaining Rust code sections, debugging compiler errors, and providing guidance on best practices. This is particularly valuable in Rust development where compiler error messages, while helpful, can sometimes be overwhelming for developers transitioning from other languages. The AI can help interpret Rust's detailed error messages and suggest fixes, making the development process more efficient by reducing the time spent deciphering compilation issues.\n",[49,1899],{"alt":1890,"src":1900},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314537/depxztu1h89bez3ylwk3.png","\nGitLab Duo Chat can also be used directly from Vulnerability Report to explain a vulnerability. GitLab Duo ",[16,1903,1906],{"href":1904,"rel":1905},"https://about.gitlab.com/blog/automate-remediation-with-ready-to-merge-ai-code-fixes/",[],"Vulnerability Explanation"," represents a significant advancement in making application security more accessible and actionable for development teams. Rather than simply flagging potential issues with cryptic error codes. or technical jargon, AI breaks down each vulnerability's nature, potential impact, and remediation steps in terms that developers at all skill levels can quickly grasp. This democratization of security knowledge accelerates the remediation process, reduces the back-and-forth between security and development teams, and ultimately helps organizations ship more secure code faster:\n",[49,1909],{"alt":1910,"src":1911},"Vulnerability Explain 1","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405091/rrcenbfazhhulmrp99yx.png"," ",[49,1914],{"alt":1915,"src":1916},"Vulnerability Explain 2","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405094/b3o4lkexyn9lp41ib8ye.png",[49,1918],{"alt":1919,"src":1920},"Vulnerability Explain 3","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405095/y56wq8j5tg10t4dgbgfq.png",[49,1922],{"alt":1923,"src":1924},"Vulnerability Explain 4","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405090/mpc1mst4ydijpqdtlljm.png",[16,1926,1929],{"href":1927,"rel":1928},"https://docs.gitlab.com/user/gitlab_duo_chat/agentic_chat/",[],"Agentic Chat",[59,1931,1932],{},"Cargo.toml",[75,1934,1936],{"id":1935},"gitlab-duo-vulnerability-resolution","GitLab Duo Vulnerability Resolution",[12,1938,1939,1940,1945,1946,1912],{},"GitLab Duo ",[16,1941,1944],{"href":1942,"rel":1943},"https://docs.gitlab.com/user/application_security/vulnerabilities/#vulnerability-resolution",[],"Vulnerability Resolution"," uses AI to automatically generate specific code fixes for detected security issues, dramatically reducing remediation time from hours to minutes. AI analyzes vulnerable code patterns and proposes precise patches tailored to the project's context, language, and dependencies while maintaining code functionality and style consistency. This automation is particularly effective for common vulnerabilities like SQL injection and cross-site scripting, enabling development teams to maintain velocity while significantly improving their security posture without disrupting the development workflow.\n",[49,1947],{"alt":1948,"src":1949},"Duo Remediate Example 1","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405090/blpwclp68igekkecbyna.png",[49,1951],{"alt":1952,"src":1953},"Duo Remediate Example 2","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405090/avvncsspwyirtk14jdbe.png",[75,1955,1957],{"id":1956},"gitlab-duo-code-review","GitLab Duo Code Review",[12,1959,1960,1961,1966,1967,1912],{},"GitLab Duo's ",[16,1962,1965],{"href":1963,"rel":1964},"https://docs.gitlab.com/user/project/merge_requests/duo_in_merge_requests/#have-gitlab-duo-review-your-code",[],"AI-powered code review"," enhances the development process by providing intelligent, automated feedback on MRs before human reviewers engage. AI analyzes code changes for potential bugs, security vulnerabilities, performance issues, and adherence to coding standards, offering contextual suggestions and explanations that help developers catch issues early. By augmenting traditional peer reviews with consistent, immediate AI insights, this feature reduces the burden on senior developers, accelerates the review cycle, and ensures that basic quality checks are consistently applied across all code contributions, ultimately improving code quality while allowing human reviewers to focus on higher-level architectural and business logic concerns.\n",[49,1968],{"alt":1969,"src":1970},"Duo Code Review 1","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405090/hewxrp2f22mf2fe4daaa.png",[49,1972],{"alt":1973,"src":1974},"Duo Code Review 2","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756405091/qbw1gi0l4ngysnyjwoy8.png",[16,1976,1978],{"href":1866,"rel":1977},[],"GitLab Duo solution page",[23,1980,1982],{"id":1981},"the-gitlab-advantage-for-rust","The GitLab advantage for Rust",[12,1984,1985,1986,1989,1990,1993,1994,1997,1998,2001,2002,2005,2006,1989,2009,2012,2013,2016,2017,2020,2021,1989,2024,2027,2028,2031,2032,2035,2036,2039,2040,95],{},"GitLab provides a complete development platform that matches Rust's comprehensive approach:\n",[83,1987,1988],{},"Integrated Workflow:"," - ",[83,1991,1992],{},"Single Platform:"," Code, CI/CD, security, and deployment in one place - ",[83,1995,1996],{},"Rust-optimized:"," Docker-based builds perfect for Rust's toolchain - ",[83,1999,2000],{},"Security First:"," Built-in security scanning - ",[83,2003,2004],{},"Enterprise-ready:"," Scalable infrastructure for large teams\n",[83,2007,2008],{},"Performance Benefits:",[83,2010,2011],{},"Efficient Caching:"," Speeds up Rust's longer compilation times - ",[83,2014,2015],{},"Parallel Builds:"," Maximizes GitLab Runner efficiency - ",[83,2018,2019],{},"Artifact Management:"," Streamlined binary distribution\n",[83,2022,2023],{},"Developer Experience:",[83,2025,2026],{},"Familiar Tools:"," Leverage standard Rust tooling (Cargo, Clippy, rustfmt) - ",[83,2029,2030],{},"Visual Feedback:"," Comprehensive dashboards and reporting - ",[83,2033,2034],{},"Automation:"," Reduces manual deployment and testing overhead - ",[83,2037,2038],{},"GitLab Duo AI:"," Ship more secure software faster with AI throughout the entire software development lifecycle\nGitLab's platform capabilities perfectly complement Rust's strengths, creating an ecosystem where safety, performance, and developer productivity converge. Rust applications on GitLab represent the cutting edge of software development—powered by a platform that understands and enhances the Rust development experience.\nTo learn more about the benefits of GitLab, sign up for a ",[16,2041,2044],{"href":2042,"rel":2043},"https://about.gitlab.com/free-trial/",[],"free trial of GitLab Ultimate with Duo Enterprise",[2046,2047,2048],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}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 .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}",{"title":102,"searchDepth":116,"depth":116,"links":2050},[2051,2052,2056,2060,2061,2064,2067,2073],{"id":25,"depth":116,"text":26},{"id":69,"depth":116,"text":70,"children":2053},[2054,2055],{"id":77,"depth":134,"text":78},{"id":584,"depth":134,"text":585},{"id":861,"depth":116,"text":862,"children":2057},[2058,2059],{"id":885,"depth":134,"text":886},{"id":1060,"depth":134,"text":1061},{"id":1190,"depth":116,"text":1191},{"id":1457,"depth":116,"text":1458,"children":2062},[2063],{"id":1473,"depth":134,"text":1474},{"id":1677,"depth":116,"text":1678,"children":2065},[2066],{"id":1684,"depth":134,"text":1685},{"id":1860,"depth":116,"text":1861,"children":2068},[2069,2070,2071,2072],{"id":1878,"depth":134,"text":1879},{"id":1889,"depth":134,"text":1890},{"id":1935,"depth":134,"text":1936},{"id":1956,"depth":134,"text":1957},{"id":1981,"depth":116,"text":1982},"engineering","2025-09-02","Learn how GitLab supports Rust development through its CI/CD capabilities, security scanning, dedicated Rust integrations, AI features, and more.","md",null,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1756314674/tct6zf6evw0xgddd2vo3.png",{},"/en-us/blog/secure-rust-development-with-gitlab",{"config":2083,"title":5,"description":2076},{"noIndex":2084},false,"secure-rust-development-with-gitlab","en-us/blog/secure-rust-development-with-gitlab",[2088,2089,2090],"community","open source","tutorial","BlogPost","4fjcc3yy94I0cngk1o98oPgM_w9LzamP0le2u8SF7PI",{"logo":2094,"freeTrial":2099,"sales":2104,"login":2109,"items":2114,"search":2438,"minimal":2469,"duo":2488,"switchNav":2497,"pricingDeployment":2508},{"config":2095},{"href":2096,"dataGaName":2097,"dataGaLocation":2098},"/","gitlab logo","header",{"text":2100,"config":2101},"Get free trial",{"href":2102,"dataGaName":2103,"dataGaLocation":2098},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":2105,"config":2106},"Request a demo",{"href":2107,"dataGaName":2108,"dataGaLocation":2098},"/sales/?contact-topic=request-demo","sales",{"text":2110,"config":2111},"Sign in",{"href":2112,"dataGaName":2113,"dataGaLocation":2098},"https://gitlab.com/users/sign_in/","sign in",[2115,2144,2242,2247,2360,2416],{"text":2116,"config":2117,"menu":2119},"Platform",{"dataNavLevelOne":2118},"platform",{"type":2120,"columns":2121},"cards",[2122,2128,2136],{"title":2116,"description":2123,"link":2124},"The intelligent orchestration platform for DevSecOps",{"text":2125,"config":2126},"Explore our Platform",{"href":2127,"dataGaName":2118,"dataGaLocation":2098},"/platform/",{"title":2129,"description":2130,"link":2131},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":2132,"config":2133},"Meet GitLab Duo",{"href":2134,"dataGaName":2135,"dataGaLocation":2098},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":2137,"description":2138,"link":2139},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":2140,"config":2141},"Learn more",{"href":2142,"dataGaName":2143,"dataGaLocation":2098},"/why-gitlab/","why gitlab",{"text":2145,"left":169,"config":2146,"menu":2148},"Product",{"dataNavLevelOne":2147},"solutions",{"type":2149,"link":2150,"columns":2154,"feature":2222},"lists",{"text":2151,"config":2152},"View all Solutions",{"href":2153,"dataGaName":2147,"dataGaLocation":2098},"/solutions/",[2155,2178,2201],{"title":2156,"description":2157,"link":2158,"items":2163},"Automation","CI/CD and automation to accelerate deployment",{"config":2159},{"icon":2160,"href":2161,"dataGaName":2162,"dataGaLocation":2098},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[2164,2167,2170,2174],{"text":20,"config":2165},{"href":2166,"dataGaLocation":2098,"dataGaName":20},"/solutions/continuous-integration/",{"text":2129,"config":2168},{"href":2134,"dataGaLocation":2098,"dataGaName":2169},"gitlab duo agent platform - product menu",{"text":2171,"config":2172},"Source Code Management",{"href":2173,"dataGaLocation":2098,"dataGaName":2171},"/solutions/source-code-management/",{"text":2175,"config":2176},"Automated Software Delivery",{"href":2161,"dataGaLocation":2098,"dataGaName":2177},"Automated software delivery",{"title":2179,"description":2180,"link":2181,"items":2186},"Security","Deliver code faster without compromising security",{"config":2182},{"href":2183,"dataGaName":2184,"dataGaLocation":2098,"icon":2185},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[2187,2191,2196],{"text":2188,"config":2189},"Application Security Testing",{"href":2183,"dataGaName":2190,"dataGaLocation":2098},"Application security testing",{"text":2192,"config":2193},"Software Supply Chain Security",{"href":2194,"dataGaLocation":2098,"dataGaName":2195},"/solutions/supply-chain/","Software supply chain security",{"text":2197,"config":2198},"Software Compliance",{"href":2199,"dataGaName":2200,"dataGaLocation":2098},"/solutions/software-compliance/","software compliance",{"title":2202,"link":2203,"items":2208},"Measurement",{"config":2204},{"icon":2205,"href":2206,"dataGaName":2207,"dataGaLocation":2098},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[2209,2213,2217],{"text":2210,"config":2211},"Visibility & Measurement",{"href":2206,"dataGaLocation":2098,"dataGaName":2212},"Visibility and Measurement",{"text":2214,"config":2215},"Value Stream Management",{"href":2216,"dataGaLocation":2098,"dataGaName":2214},"/solutions/value-stream-management/",{"text":2218,"config":2219},"Analytics & Insights",{"href":2220,"dataGaLocation":2098,"dataGaName":2221},"/solutions/analytics-and-insights/","Analytics and insights",{"title":2223,"type":2149,"items":2224},"GitLab for",[2225,2230,2236],{"text":2226,"config":2227},"Enterprise",{"icon":78,"href":2228,"dataGaLocation":2098,"dataGaName":2229},"/enterprise/","enterprise",{"text":2231,"config":2232},"Small Business",{"icon":2233,"href":2234,"dataGaLocation":2098,"dataGaName":2235},"Work","/small-business/","small business",{"text":2237,"config":2238},"Public Sector",{"icon":2239,"href":2240,"dataGaLocation":2098,"dataGaName":2241},"Organization","/solutions/public-sector/","public sector",{"text":2243,"config":2244},"Pricing",{"href":2245,"dataGaName":2246,"dataGaLocation":2098,"dataNavLevelOne":2246},"/pricing/","pricing",{"text":2248,"config":2249,"menu":2251},"Resources",{"dataNavLevelOne":2250},"resources",{"type":2149,"link":2252,"columns":2256,"feature":2349},{"text":2253,"config":2254},"View all resources",{"href":2255,"dataGaName":2250,"dataGaLocation":2098},"/resources/",[2257,2290,2317],{"title":2258,"items":2259},"Getting started",[2260,2265,2270,2275,2280,2285],{"text":2261,"config":2262},"Install",{"href":2263,"dataGaName":2264,"dataGaLocation":2098},"/install/","install",{"text":2266,"config":2267},"Quick start guides",{"href":2268,"dataGaName":2269,"dataGaLocation":2098},"/get-started/","quick setup checklists",{"text":2271,"config":2272},"Learn",{"href":2273,"dataGaLocation":2098,"dataGaName":2274},"https://university.gitlab.com/","learn",{"text":2276,"config":2277},"Product documentation",{"href":2278,"dataGaName":2279,"dataGaLocation":2098},"https://docs.gitlab.com/","product documentation",{"text":2281,"config":2282},"Best practice videos",{"href":2283,"dataGaName":2284,"dataGaLocation":2098},"/getting-started-videos/","best practice videos",{"text":2286,"config":2287},"Integrations",{"href":2288,"dataGaName":2289,"dataGaLocation":2098},"/integrations/","integrations",{"title":2291,"items":2292},"Discover",[2293,2298,2303,2308,2312],{"text":2294,"config":2295},"Customer success stories",{"href":2296,"dataGaName":2297,"dataGaLocation":2098},"/customers/","customer success stories",{"text":2299,"config":2300},"Blog",{"href":2301,"dataGaName":2302,"dataGaLocation":2098},"/blog/","blog",{"text":2304,"config":2305},"Demo Hub",{"href":2306,"dataGaName":2307,"dataGaLocation":2098},"/demo-hub/","demo hub",{"text":2309,"config":2310},"The Source",{"href":2311,"dataGaName":2302,"dataGaLocation":2098},"/the-source/",{"text":2313,"config":2314},"Remote",{"href":2315,"dataGaName":2316,"dataGaLocation":2098},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":2318,"items":2319},"Connect",[2320,2325,2330,2334,2339,2344],{"text":2321,"config":2322},"GitLab Services",{"href":2323,"dataGaName":2324,"dataGaLocation":2098},"/services/","services",{"text":2326,"config":2327},"Contribute",{"href":2328,"dataGaName":2329,"dataGaLocation":2098},"https://contributors.gitlab.com","contribute",{"text":2331,"config":2332},"Community",{"href":2333,"dataGaName":2088,"dataGaLocation":2098},"/community/",{"text":2335,"config":2336},"Forum",{"href":2337,"dataGaName":2338,"dataGaLocation":2098},"https://forum.gitlab.com/","forum",{"text":2340,"config":2341},"Events",{"href":2342,"dataGaName":2343,"dataGaLocation":2098},"/events/","events",{"text":2345,"config":2346},"Partners",{"href":2347,"dataGaName":2348,"dataGaLocation":2098},"/partners/","partners",{"config":2350,"title":2353,"text":2354,"link":2355},{"background":2351,"textColor":2352},"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":2356,"config":2357},"Read the latest",{"href":2358,"dataGaName":2359,"dataGaLocation":2098},"/whats-new/","whats new",{"text":2361,"config":2362,"menu":2364},"Company",{"dataNavLevelOne":2363},"company",{"type":2149,"columns":2365},[2366],{"items":2367},[2368,2373,2379,2381,2386,2391,2396,2401,2406,2411],{"text":2369,"config":2370},"About",{"href":2371,"dataGaName":2372,"dataGaLocation":2098},"/company/","about",{"text":2374,"config":2375,"footerGa":2378},"Jobs",{"href":2376,"dataGaName":2377,"dataGaLocation":2098},"/jobs/","jobs",{"dataGaName":2377},{"text":2340,"config":2380},{"href":2342,"dataGaName":2343,"dataGaLocation":2098},{"text":2382,"config":2383},"Leadership",{"href":2384,"dataGaName":2385,"dataGaLocation":2098},"/company/team/e-group/","leadership",{"text":2387,"config":2388},"Handbook",{"href":2389,"dataGaName":2390,"dataGaLocation":2098},"https://handbook.gitlab.com/","handbook",{"text":2392,"config":2393},"Investor relations",{"href":2394,"dataGaName":2395,"dataGaLocation":2098},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":2397,"config":2398},"Trust Center",{"href":2399,"dataGaName":2400,"dataGaLocation":2098},"/security/","trust center",{"text":2402,"config":2403},"AI Transparency Center",{"href":2404,"dataGaName":2405,"dataGaLocation":2098},"/ai-transparency-center/","ai transparency center",{"text":2407,"config":2408},"Newsletter",{"href":2409,"dataGaName":2410,"dataGaLocation":2098},"/company/contact/#contact-forms","newsletter",{"text":2412,"config":2413},"Press",{"href":2414,"dataGaName":2415,"dataGaLocation":2098},"/press/","press",{"text":2417,"config":2418,"menu":2419},"Contact us",{"dataNavLevelOne":2363},{"type":2149,"columns":2420},[2421],{"items":2422},[2423,2428,2433],{"text":2424,"config":2425},"Talk to sales",{"href":2426,"dataGaName":2427,"dataGaLocation":2098},"/sales/","talk to sales",{"text":2429,"config":2430},"Support portal",{"href":2431,"dataGaName":2432,"dataGaLocation":2098},"https://support.gitlab.com/hc/en-us","support portal",{"text":2434,"config":2435},"Customer portal",{"href":2436,"dataGaName":2437,"dataGaLocation":2098},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":2439,"login":2440,"suggestions":2447},"Close",{"text":2441,"link":2442},"To search repositories and projects, login to",{"text":2443,"config":2444},"gitlab.com",{"href":2112,"dataGaName":2445,"dataGaLocation":2446},"search login","search",{"text":2448,"default":2449},"Suggestions",[2450,2452,2456,2458,2462,2466],{"text":2129,"config":2451},{"href":2134,"dataGaName":2129,"dataGaLocation":2446},{"text":2453,"config":2454},"Code Suggestions (AI)",{"href":2455,"dataGaName":2453,"dataGaLocation":2446},"/solutions/code-suggestions/",{"text":20,"config":2457},{"href":2166,"dataGaName":20,"dataGaLocation":2446},{"text":2459,"config":2460},"GitLab on AWS",{"href":2461,"dataGaName":2459,"dataGaLocation":2446},"/partners/technology-partners/aws/",{"text":2463,"config":2464},"GitLab on Google Cloud",{"href":2465,"dataGaName":2463,"dataGaLocation":2446},"/partners/technology-partners/google-cloud-platform/",{"text":2467,"config":2468},"Why GitLab?",{"href":2142,"dataGaName":2467,"dataGaLocation":2446},{"freeTrial":2470,"mobileIcon":2475,"desktopIcon":2480,"secondaryButton":2483},{"text":2471,"config":2472},"Start free trial",{"href":2473,"dataGaName":2103,"dataGaLocation":2474},"https://gitlab.com/-/trials/new/","nav",{"altText":2476,"config":2477},"Gitlab Icon",{"src":2478,"dataGaName":2479,"dataGaLocation":2474},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":2476,"config":2481},{"src":2482,"dataGaName":2479,"dataGaLocation":2474},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":2484,"config":2485},"Get Started",{"href":2486,"dataGaName":2487,"dataGaLocation":2474},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":2489,"mobileIcon":2493,"desktopIcon":2495},{"text":2490,"config":2491},"Learn more about GitLab Duo",{"href":2134,"dataGaName":2492,"dataGaLocation":2474},"gitlab duo",{"altText":2476,"config":2494},{"src":2478,"dataGaName":2479,"dataGaLocation":2474},{"altText":2476,"config":2496},{"src":2482,"dataGaName":2479,"dataGaLocation":2474},{"button":2498,"mobileIcon":2503,"desktopIcon":2505},{"text":2499,"config":2500},"/switch",{"href":2501,"dataGaName":2502,"dataGaLocation":2474},"#contact","switch",{"altText":2476,"config":2504},{"src":2478,"dataGaName":2479,"dataGaLocation":2474},{"altText":2476,"config":2506},{"src":2507,"dataGaName":2479,"dataGaLocation":2474},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":2509,"mobileIcon":2514,"desktopIcon":2516},{"text":2510,"config":2511},"Back to pricing",{"href":2245,"dataGaName":2512,"dataGaLocation":2474,"icon":2513},"back to pricing","GoBack",{"altText":2476,"config":2515},{"src":2478,"dataGaName":2479,"dataGaLocation":2474},{"altText":2476,"config":2517},{"src":2482,"dataGaName":2479,"dataGaLocation":2474},{"title":2519,"titleMobile":2520,"button":2521,"config":2526},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":2140,"config":2522},{"href":2523,"dataGaName":2524,"dataGaLocation":2525},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":2527,"disabled":2084},"release",{"data":2529},{"text":2530,"source":2531,"edit":2537,"contribute":2542,"config":2547,"items":2552,"minimal":2762},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":2532,"config":2533},"View page source",{"href":2534,"dataGaName":2535,"dataGaLocation":2536},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":2538,"config":2539},"Edit this page",{"href":2540,"dataGaName":2541,"dataGaLocation":2536},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":2543,"config":2544},"Please contribute",{"href":2545,"dataGaName":2546,"dataGaLocation":2536},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":2548,"facebook":2549,"youtube":2550,"linkedin":2551},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[2553,2600,2654,2698,2730],{"title":2243,"links":2554,"subMenu":2569},[2555,2559,2564],{"text":2556,"config":2557},"View plans",{"href":2245,"dataGaName":2558,"dataGaLocation":2536},"view plans",{"text":2560,"config":2561},"Why Premium?",{"href":2562,"dataGaName":2563,"dataGaLocation":2536},"/pricing/premium/","why premium",{"text":2565,"config":2566},"Why Ultimate?",{"href":2567,"dataGaName":2568,"dataGaLocation":2536},"/pricing/ultimate/","why ultimate",[2570],{"title":2571,"links":2572},"Contact Us",[2573,2576,2578,2580,2585,2590,2595],{"text":2574,"config":2575},"Contact sales",{"href":2426,"dataGaName":2108,"dataGaLocation":2536},{"text":2429,"config":2577},{"href":2431,"dataGaName":2432,"dataGaLocation":2536},{"text":2434,"config":2579},{"href":2436,"dataGaName":2437,"dataGaLocation":2536},{"text":2581,"config":2582},"Status",{"href":2583,"dataGaName":2584,"dataGaLocation":2536},"https://status.gitlab.com/","status",{"text":2586,"config":2587},"Terms of use",{"href":2588,"dataGaName":2589,"dataGaLocation":2536},"/terms/","terms of use",{"text":2591,"config":2592},"Privacy statement",{"href":2593,"dataGaName":2594,"dataGaLocation":2536},"/privacy/","privacy statement",{"text":2596,"config":2597},"Cookie preferences",{"dataGaName":2598,"dataGaLocation":2536,"id":2599,"isOneTrustButton":169},"cookie preferences","ot-sdk-btn",{"title":2145,"links":2601,"subMenu":2610},[2602,2606],{"text":2603,"config":2604},"DevSecOps platform",{"href":2127,"dataGaName":2605,"dataGaLocation":2536},"devsecops platform",{"text":2607,"config":2608},"AI-Assisted Development",{"href":2134,"dataGaName":2609,"dataGaLocation":2536},"ai-assisted development",[2611],{"title":2612,"links":2613},"Topics",[2614,2619,2624,2629,2634,2639,2644,2649],{"text":2615,"config":2616},"CICD",{"href":2617,"dataGaName":2618,"dataGaLocation":2536},"/topics/ci-cd/","cicd",{"text":2620,"config":2621},"GitOps",{"href":2622,"dataGaName":2623,"dataGaLocation":2536},"/topics/gitops/","gitops",{"text":2625,"config":2626},"DevOps",{"href":2627,"dataGaName":2628,"dataGaLocation":2536},"/topics/devops/","devops",{"text":2630,"config":2631},"Version Control",{"href":2632,"dataGaName":2633,"dataGaLocation":2536},"/topics/version-control/","version control",{"text":2635,"config":2636},"DevSecOps",{"href":2637,"dataGaName":2638,"dataGaLocation":2536},"/topics/devsecops/","devsecops",{"text":2640,"config":2641},"Cloud Native",{"href":2642,"dataGaName":2643,"dataGaLocation":2536},"/topics/cloud-native/","cloud native",{"text":2645,"config":2646},"AI for Coding",{"href":2647,"dataGaName":2648,"dataGaLocation":2536},"/topics/devops/ai-for-coding/","ai for coding",{"text":2650,"config":2651},"Agentic AI",{"href":2652,"dataGaName":2653,"dataGaLocation":2536},"/topics/agentic-ai/","agentic ai",{"title":2655,"links":2656},"Solutions",[2657,2659,2661,2666,2670,2673,2677,2680,2682,2685,2688,2693],{"text":2188,"config":2658},{"href":2183,"dataGaName":2188,"dataGaLocation":2536},{"text":2177,"config":2660},{"href":2161,"dataGaName":2162,"dataGaLocation":2536},{"text":2662,"config":2663},"Agile development",{"href":2664,"dataGaName":2665,"dataGaLocation":2536},"/solutions/agile-delivery/","agile delivery",{"text":2667,"config":2668},"SCM",{"href":2173,"dataGaName":2669,"dataGaLocation":2536},"source code management",{"text":2615,"config":2671},{"href":2166,"dataGaName":2672,"dataGaLocation":2536},"continuous integration & delivery",{"text":2674,"config":2675},"Value stream management",{"href":2216,"dataGaName":2676,"dataGaLocation":2536},"value stream management",{"text":2620,"config":2678},{"href":2679,"dataGaName":2623,"dataGaLocation":2536},"/solutions/gitops/",{"text":2226,"config":2681},{"href":2228,"dataGaName":2229,"dataGaLocation":2536},{"text":2683,"config":2684},"Small business",{"href":2234,"dataGaName":2235,"dataGaLocation":2536},{"text":2686,"config":2687},"Public sector",{"href":2240,"dataGaName":2241,"dataGaLocation":2536},{"text":2689,"config":2690},"Education",{"href":2691,"dataGaName":2692,"dataGaLocation":2536},"/solutions/education/","education",{"text":2694,"config":2695},"Financial services",{"href":2696,"dataGaName":2697,"dataGaLocation":2536},"/solutions/finance/","financial services",{"title":2248,"links":2699},[2700,2702,2704,2706,2709,2711,2714,2716,2718,2720,2722,2724,2726,2728],{"text":2261,"config":2701},{"href":2263,"dataGaName":2264,"dataGaLocation":2536},{"text":2266,"config":2703},{"href":2268,"dataGaName":2269,"dataGaLocation":2536},{"text":2271,"config":2705},{"href":2273,"dataGaName":2274,"dataGaLocation":2536},{"text":2276,"config":2707},{"href":2278,"dataGaName":2708,"dataGaLocation":2536},"docs",{"text":2299,"config":2710},{"href":2301,"dataGaName":2302,"dataGaLocation":2536},{"text":2712,"config":2713},"What's new",{"href":2358,"dataGaName":2359,"dataGaLocation":2536},{"text":2294,"config":2715},{"href":2296,"dataGaName":2297,"dataGaLocation":2536},{"text":2313,"config":2717},{"href":2315,"dataGaName":2316,"dataGaLocation":2536},{"text":2321,"config":2719},{"href":2323,"dataGaName":2324,"dataGaLocation":2536},{"text":2326,"config":2721},{"href":2328,"dataGaName":2329,"dataGaLocation":2536},{"text":2331,"config":2723},{"href":2333,"dataGaName":2088,"dataGaLocation":2536},{"text":2335,"config":2725},{"href":2337,"dataGaName":2338,"dataGaLocation":2536},{"text":2340,"config":2727},{"href":2342,"dataGaName":2343,"dataGaLocation":2536},{"text":2345,"config":2729},{"href":2347,"dataGaName":2348,"dataGaLocation":2536},{"title":2361,"links":2731},[2732,2734,2736,2738,2740,2742,2746,2751,2753,2755,2757],{"text":2369,"config":2733},{"href":2371,"dataGaName":2363,"dataGaLocation":2536},{"text":2374,"config":2735},{"href":2376,"dataGaName":2377,"dataGaLocation":2536},{"text":2382,"config":2737},{"href":2384,"dataGaName":2385,"dataGaLocation":2536},{"text":2387,"config":2739},{"href":2389,"dataGaName":2390,"dataGaLocation":2536},{"text":2392,"config":2741},{"href":2394,"dataGaName":2395,"dataGaLocation":2536},{"text":2743,"config":2744},"Sustainability",{"href":2745,"dataGaName":2743,"dataGaLocation":2536},"/sustainability/",{"text":2747,"config":2748},"Diversity, inclusion and belonging (DIB)",{"href":2749,"dataGaName":2750,"dataGaLocation":2536},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":2397,"config":2752},{"href":2399,"dataGaName":2400,"dataGaLocation":2536},{"text":2407,"config":2754},{"href":2409,"dataGaName":2410,"dataGaLocation":2536},{"text":2412,"config":2756},{"href":2414,"dataGaName":2415,"dataGaLocation":2536},{"text":2758,"config":2759},"Modern Slavery Transparency Statement",{"href":2760,"dataGaName":2761,"dataGaLocation":2536},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":2763},[2764,2767,2770],{"text":2765,"config":2766},"Terms",{"href":2588,"dataGaName":2589,"dataGaLocation":2536},{"text":2768,"config":2769},"Cookies",{"dataGaName":2598,"dataGaLocation":2536,"id":2599,"isOneTrustButton":169},{"text":2771,"config":2772},"Privacy",{"href":2593,"dataGaName":2594,"dataGaLocation":2536},[2774],{"id":2775,"title":7,"body":2078,"config":2776,"content":2778,"description":2078,"extension":2782,"meta":2783,"navigation":169,"path":2784,"seo":2785,"stem":2786,"__hash__":2787},"blogAuthors/en-us/blog/authors/fernando-diaz.yml",{"template":2777},"BlogAuthor",{"name":7,"config":2779},{"headshot":2780,"ctfId":2781},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659556/Blog/Author%20Headshots/fern_diaz.png","fjdiaz","yml",{},"/en-us/blog/authors/fernando-diaz",{},"en-us/blog/authors/fernando-diaz","lxRJIOydP4_yzYZvsPcuQevP9AYAKREF7i8QmmdnOWc",[2789,2798,2806],{"title":2790,"description":2791,"heroImage":2792,"category":2074,"date":2793,"authors":2794,"slug":2797,"externalUrl":2078},"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",[2795,2796],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":2799,"description":2800,"heroImage":2801,"category":2074,"date":2802,"authors":2803,"slug":2805,"externalUrl":2078},"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",[2804],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":2807,"description":2808,"heroImage":2809,"category":2074,"date":2810,"authors":2811,"slug":2813,"externalUrl":2078},"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",[2812],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":2815},[2816,2830,2842,2854],{"id":2817,"categories":2818,"header":2820,"text":2821,"button":2822,"image":2827},"ai-modernization",[2819],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":2823,"config":2824},"Get your AI maturity score",{"href":2825,"dataGaName":2826,"dataGaLocation":2302},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":2828},{"src":2829},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":2831,"categories":2832,"header":2834,"text":2821,"button":2835,"image":2839},"devops-modernization",[2833,2638],"product","Are you just managing tools or shipping innovation?",{"text":2836,"config":2837},"Get your DevOps maturity score",{"href":2838,"dataGaName":2826,"dataGaLocation":2302},"/assessments/devops-modernization-assessment/",{"config":2840},{"src":2841},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":2843,"categories":2844,"header":2846,"text":2821,"button":2847,"image":2851},"security-modernization",[2845],"security","Are you trading speed for security?",{"text":2848,"config":2849},"Get your security maturity score",{"href":2850,"dataGaName":2826,"dataGaLocation":2302},"/assessments/security-modernization-assessment/",{"config":2852},{"src":2853},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":2855,"paths":2856,"header":2859,"text":2860,"button":2861,"image":2866},"github-azure-migration",[2857,2858],"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":2862,"config":2863},"See how GitLab compares to GitHub",{"href":2864,"dataGaName":2865,"dataGaLocation":2302},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":2867},{"src":2841},{"header":2869,"blurb":2870,"button":2871,"secondaryButton":2876},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":2872,"config":2873},"Get your free trial",{"href":2874,"dataGaName":2103,"dataGaLocation":2875},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":2574,"config":2877},{"href":2426,"dataGaName":2108,"dataGaLocation":2875},1786803754475]