[{"data":1,"prerenderedAt":2154},["ShallowReactive",2],{"navigation_docs":3,"-guides-scan-from-another-ci":114,"-guides-scan-from-another-ci-surround":2149},[4,23,85,99],{"title":5,"path":6,"stem":7,"children":8},"Getting Started","\u002Fgetting-started","1.getting-started",[9,13,18],{"title":10,"path":6,"stem":11,"icon":12},"Getting started","1.getting-started\u002Findex","i-lucide-rocket",{"title":14,"path":15,"stem":16,"icon":17},"Try the demo","\u002Fgetting-started\u002Ftry-the-demo","1.getting-started\u002F1.try-the-demo","i-lucide-monitor-play",{"title":19,"path":20,"stem":21,"icon":22},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F2.quickstart","i-lucide-play",{"title":24,"path":25,"stem":26,"children":27},"Guides","\u002Fguides","2.guides",[28,31,37,42,47,53,58,63,68,74,80],{"title":24,"path":25,"stem":29,"icon":30},"2.guides\u002Findex","i-lucide-map",{"title":32,"path":33,"stem":34,"icon":35,"group":36},"Connect a GitHub repository","\u002Fguides\u002Fconnect-a-github-repository","2.guides\u002F01.connect-a-github-repository","i-lucide-git-branch","Connect a project",{"title":38,"path":39,"stem":40,"icon":41,"group":36},"Analyze a project without GitHub","\u002Fguides\u002Fanalyze-a-project-without-github","2.guides\u002F02.analyze-a-project-without-github","i-lucide-upload",{"title":43,"path":44,"stem":45,"icon":46,"group":36},"Exclude dependency scopes","\u002Fguides\u002Fexclude-dependency-scopes","2.guides\u002F04.exclude-dependency-scopes","i-lucide-filter",{"title":48,"path":49,"stem":50,"icon":51,"group":52},"Scan from GitHub Actions","\u002Fguides\u002Fscan-from-github-actions","2.guides\u002F05.scan-from-github-actions","i-lucide-workflow","Automate",{"title":54,"path":55,"stem":56,"icon":57,"group":52},"Scan from another CI","\u002Fguides\u002Fscan-from-another-ci","2.guides\u002F06.scan-from-another-ci","i-lucide-square-terminal",{"title":59,"path":60,"stem":61,"icon":62,"group":52},"Manage API keys","\u002Fguides\u002Fmanage-api-keys","2.guides\u002F07.manage-api-keys","i-lucide-key-round",{"title":64,"path":65,"stem":66,"icon":67,"group":52},"Create many projects at once","\u002Fguides\u002Fcreate-many-projects-at-once","2.guides\u002F08.create-many-projects-at-once","i-lucide-layers",{"title":69,"path":70,"stem":71,"icon":72,"group":73},"Export reports and SBOMs","\u002Fguides\u002Fexport-reports-and-sboms","2.guides\u002F11.export-reports-and-sboms","i-lucide-download","Act on the results",{"title":75,"path":76,"stem":77,"icon":78,"group":79},"Organizations and plans","\u002Fguides\u002Forganizations-and-plans","2.guides\u002F13.organizations-and-plans","i-lucide-building-2","Organization and team",{"title":81,"path":82,"stem":83,"icon":84,"group":79},"Invite your team","\u002Fguides\u002Finvite-your-team","2.guides\u002F14.invite-your-team","i-lucide-users",{"title":86,"path":87,"stem":88,"children":89},"Core Concepts","\u002Fcore-concepts","3.core-concepts",[90,94],{"title":91,"path":87,"stem":92,"icon":93},"Core concepts","3.core-concepts\u002Findex","i-lucide-lightbulb",{"title":95,"path":96,"stem":97,"icon":98},"The health score","\u002Fcore-concepts\u002Fhealth-score","3.core-concepts\u002F1.health-score","i-lucide-gauge",{"title":100,"path":101,"stem":102,"children":103},"Reference","\u002Freference","5.reference",[104,107],{"title":100,"path":101,"stem":105,"icon":106},"5.reference\u002Findex","i-lucide-book-marked",{"title":108,"path":109,"stem":110,"children":111,"icon":113},"Supported ecosystems","\u002Freference\u002Fecosystems","5.reference\u002F1.ecosystems\u002Findex",[112],{"title":108,"path":109,"stem":110,"icon":113},"i-lucide-package",{"id":115,"title":54,"body":116,"description":2142,"extension":2143,"links":2144,"meta":2145,"navigation":2146,"path":55,"seo":2147,"stem":56,"__hash__":2148},"docs\u002F2.guides\u002F06.scan-from-another-ci.md",{"type":117,"value":118,"toc":2134},"minimark",[119,133,149,152,157,164,204,225,233,236,306,358,372,375,467,482,486,496,535,784,808,811,820,1439,1443,1457,1650,1653,1665,1685,1711,1715,1719,1726,1991,2000,2003,2006,2010,2013,2076,2085,2088,2111,2114,2118,2130],[120,121,122,123,127,128,132],"p",{},"Any pipeline that can run ",[124,125,126],"code",{},"curl"," can start a Deptools scan. Two endpoints do the\nwhole job: one starts the scan, one reports its status. The second returns the\nscore, the vulnerability counts, the license verdict and the freshness of your\ndirect dependencies, so you can write the same quality gates as the\n",[129,130,131],"a",{"href":49},"Deptools GitHub Action",", in your own\nshell.",[134,135,136,137,141,142,145,146,148],"note",{},"This page is for a project ",[138,139,140],"strong",{},"linked to a GitHub repository",", scanned from a\npipeline that is not GitHub Actions. On GitHub Actions, use the action: it does\nall of this for you. ",[138,143,144],{},"If your code is not on GitHub",", your pipeline sends the\nbuild files instead, see\n",[129,147,38],{"href":39},".\nThe last section separates the three cases.",[120,150,151],{},"Your runner uploads nothing. It calls the Deptools API, and Deptools reads the\nbuild file on GitHub.com through the GitHub App, on the branch configured on the\nproject. So the job needs no checkout, and it lasts a second when it does not\nwait for the result. The ref your pipeline runs on does not affect the scan.\nA scan started from a merge request still analyzes the branch configured on the project.",[153,154,156],"h2",{"id":155},"trigger-a-scan-with-curl","Trigger a scan with curl",[120,158,159,160,163],{},"You need two values, both in the ",[138,161,162],{},"Integrations"," tab of the project:",[165,166,167,180],"table",{},[168,169,170],"thead",{},[171,172,173,177],"tr",{},[174,175,176],"th",{},"Variable",[174,178,179],{},"Value",[181,182,183,194],"tbody",{},[171,184,185,191],{},[186,187,188],"td",{},[124,189,190],{},"DEPTOOLS_PROJECT_UUID",[186,192,193],{},"The project UUID, with a copy button next to it",[171,195,196,201],{},[186,197,198],{},[124,199,200],{},"DEPTOOLS_API_KEY",[186,202,203],{},"An API key. Store it as a masked or secret variable, never in the pipeline file",[120,205,206,207,210,211,214,215,210,218,221,222,224],{},"Use a ",[138,208,209],{},"project key"," (",[124,212,213],{},"dt_proj_...",") when a repository scans itself. Use an\n",[138,216,217],{},"organization key",[124,219,220],{},"dt_org_...",") when multiple pipelines scan, and store it once\nin a shared variable. ",[129,223,59],{"href":60}," covers what each\nscope reaches, who can create a key and how to rotate one.",[226,227],"u-color-mode-image",{"alt":228,"className":229,"dark":231,"light":232},"Other CI providers card of the Integrations tab, with the scan endpoint, the status endpoint and a curl example",[230],"wide-capture","\u002Fimages\u002Fdocs\u002Fguides\u002Fscan-from-another-ci-1-other-ci-card-dark.webp","\u002Fimages\u002Fdocs\u002Fguides\u002Fscan-from-another-ci-1-other-ci-card-light.webp",[120,234,235],{},"The request carries no body:",[237,238,243],"pre",{"className":239,"code":240,"language":241,"meta":242,"style":242},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl -sS -X POST \\\n  -H \"Authorization: Bearer $DEPTOOLS_API_KEY\" \\\n  \"https:\u002F\u002Fapi.deptools.io\u002Fv1\u002Fprojects\u002F$DEPTOOLS_PROJECT_UUID\u002Fscan\"\n","sh","",[124,244,245,267,288],{"__ignoreMap":242},[246,247,250,253,257,260,263],"span",{"class":248,"line":249},"line",1,[246,251,126],{"class":252},"sBMFI",[246,254,256],{"class":255},"sfazB"," -sS",[246,258,259],{"class":255}," -X",[246,261,262],{"class":255}," POST",[246,264,266],{"class":265},"sTEyZ"," \\\n",[246,268,270,273,277,280,283,286],{"class":248,"line":269},2,[246,271,272],{"class":255},"  -H",[246,274,276],{"class":275},"sMK4o"," \"",[246,278,279],{"class":255},"Authorization: Bearer ",[246,281,282],{"class":265},"$DEPTOOLS_API_KEY",[246,284,285],{"class":275},"\"",[246,287,266],{"class":265},[246,289,291,294,297,300,303],{"class":248,"line":290},3,[246,292,293],{"class":275},"  \"",[246,295,296],{"class":255},"https:\u002F\u002Fapi.deptools.io\u002Fv1\u002Fprojects\u002F",[246,298,299],{"class":265},"$DEPTOOLS_PROJECT_UUID",[246,301,302],{"class":255},"\u002Fscan",[246,304,305],{"class":275},"\"\n",[237,307,311],{"className":308,"code":309,"language":310,"meta":242,"style":242},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{ \"jobId\": \"3f9a…\", \"pollUrl\": \"\u002Fv1\u002Fscans\u002F3f9a…\u002Fstatus\" }\n","json",[124,312,313],{"__ignoreMap":242},[246,314,315,318,320,324,326,329,331,334,336,339,341,344,346,348,350,353,355],{"class":248,"line":249},[246,316,317],{"class":275},"{",[246,319,276],{"class":275},[246,321,323],{"class":322},"spNyl","jobId",[246,325,285],{"class":275},[246,327,328],{"class":275},":",[246,330,276],{"class":275},[246,332,333],{"class":255},"3f9a…",[246,335,285],{"class":275},[246,337,338],{"class":275},",",[246,340,276],{"class":275},[246,342,343],{"class":322},"pollUrl",[246,345,285],{"class":275},[246,347,328],{"class":275},[246,349,276],{"class":275},[246,351,352],{"class":255},"\u002Fv1\u002Fscans\u002F3f9a…\u002Fstatus",[246,354,285],{"class":275},[246,356,357],{"class":275}," }\n",[120,359,360,361,364,365,367,368,371],{},"A ",[124,362,363],{},"202"," means the scan was accepted, not that the analysis succeeded. ",[124,366,343],{},"\nis relative, so prefix it with ",[124,369,370],{},"https:\u002F\u002Fapi.deptools.io",". Stop here and your\npipeline is fire and forget: the analysis appears in the dashboard a few minutes\nlater and nothing can fail your build.",[120,373,374],{},"If the scan cannot be started, the body carries a message and often a code:",[165,376,377,387],{},[168,378,379],{},[171,380,381,384],{},[174,382,383],{},"HTTP",[174,385,386],{},"Cause and fix",[181,388,389,400,411,419,427,438,453],{},[171,390,391,394],{},[186,392,393],{},"401",[186,395,396,397],{},"The key is missing or malformed. The header is ",[124,398,399],{},"Authorization: Bearer dt_org_...",[171,401,402,408],{},[186,403,404,405],{},"401 ",[124,406,407],{},"API_KEY_EXPIRED",[186,409,410],{},"The key passed its expiration date. Create a new one",[171,412,413,416],{},[186,414,415],{},"403",[186,417,418],{},"The key is not allowed to run scans. A key created only to provision projects cannot scan, and no key ever gains a permission after creation",[171,420,421,424],{},[186,422,423],{},"404",[186,425,426],{},"Unknown UUID, or a project outside the key's scope. A project key reaches its own project only, and the answer is deliberately the same in both cases",[171,428,429,435],{},[186,430,431,432],{},"400 ",[124,433,434],{},"BUNDLE_REQUIRED",[186,436,437],{},"The project is a CI upload project, which expects your build files rather than a bare trigger. See the last section",[171,439,440,446],{},[186,441,442,443],{},"429 ",[124,444,445],{},"SCAN_RATE_LIMITED",[186,447,448,449,452],{},"The cooldown of the plan is still active. The body carries ",[124,450,451],{},"retryAfter",", an ISO date",[171,454,455,458],{},[186,456,457],{},"429",[186,459,460,461,463,464,466],{},"More than 60 scans were requested in the last hour, from this IP address and on this project. It carries no ",[124,462,124],{},", so ",[124,465,451],{}," is what tells it apart from the cooldown",[468,469,470,471,474,475,477,478,481],"warning",{},"On the ",[138,472,473],{},"Free"," plan, Deptools accepts one scan every three hours per project configuration. A pipeline that runs on every push will therefore get a ",[124,476,457],{}," most of the time.\nThe script below skips these runs and stays green, so the cooldown never turns into a failed build. But a skipped scan does not protect your merges. If merges must be gated on the result, the Pro plan removes the cooldown.\n",[129,479,75],{"href":480},"\u002Fguides\u002Forganizations-and-plans#the-scan-cooldown","\ndefines what a configuration is and what counts against the cooldown.",[153,483,485],{"id":484},"wait-for-the-result","Wait for the result",[120,487,488,489,492,493,328],{},"Poll the status endpoint with the same key until ",[124,490,491],{},"status"," leaves ",[124,494,495],{},"running",[237,497,499],{"className":239,"code":498,"language":241,"meta":242,"style":242},"curl -sS -H \"Authorization: Bearer $DEPTOOLS_API_KEY\" \\\n  \"https:\u002F\u002Fapi.deptools.io\u002Fv1\u002Fscans\u002F$JOB_ID\u002Fstatus\"\n",[124,500,501,520],{"__ignoreMap":242},[246,502,503,505,507,510,512,514,516,518],{"class":248,"line":249},[246,504,126],{"class":252},[246,506,256],{"class":255},[246,508,509],{"class":255}," -H",[246,511,276],{"class":275},[246,513,279],{"class":255},[246,515,282],{"class":265},[246,517,285],{"class":275},[246,519,266],{"class":265},[246,521,522,524,527,530,533],{"class":248,"line":269},[246,523,293],{"class":275},[246,525,526],{"class":255},"https:\u002F\u002Fapi.deptools.io\u002Fv1\u002Fscans\u002F",[246,528,529],{"class":265},"$JOB_ID",[246,531,532],{"class":255},"\u002Fstatus",[246,534,305],{"class":275},[237,536,538],{"className":308,"code":537,"language":310,"meta":242,"style":242},"{\n  \"jobId\": \"3f9a…\",\n  \"status\": \"completed\",\n  \"createdAt\": \"2026-08-09T10:00:00.000Z\",\n  \"result\": {\n    \"overall_score\": 7.4,\n    \"dependency_number\": 182,\n    \"vulnerabilities_by_severity\": { \"CRITICAL\": 0, \"HIGH\": 2, \"MODERATE\": 5, \"LOW\": 1 },\n    \"commercial_use\": false,\n    \"direct_up_to_date\": 84\n  },\n  \"error\": null\n}\n",[124,539,540,545,564,583,604,619,638,655,727,742,757,763,778],{"__ignoreMap":242},[246,541,542],{"class":248,"line":249},[246,543,544],{"class":275},"{\n",[246,546,547,549,551,553,555,557,559,561],{"class":248,"line":269},[246,548,293],{"class":275},[246,550,323],{"class":322},[246,552,285],{"class":275},[246,554,328],{"class":275},[246,556,276],{"class":275},[246,558,333],{"class":255},[246,560,285],{"class":275},[246,562,563],{"class":275},",\n",[246,565,566,568,570,572,574,576,579,581],{"class":248,"line":290},[246,567,293],{"class":275},[246,569,491],{"class":322},[246,571,285],{"class":275},[246,573,328],{"class":275},[246,575,276],{"class":275},[246,577,578],{"class":255},"completed",[246,580,285],{"class":275},[246,582,563],{"class":275},[246,584,586,588,591,593,595,597,600,602],{"class":248,"line":585},4,[246,587,293],{"class":275},[246,589,590],{"class":322},"createdAt",[246,592,285],{"class":275},[246,594,328],{"class":275},[246,596,276],{"class":275},[246,598,599],{"class":255},"2026-08-09T10:00:00.000Z",[246,601,285],{"class":275},[246,603,563],{"class":275},[246,605,607,609,612,614,616],{"class":248,"line":606},5,[246,608,293],{"class":275},[246,610,611],{"class":322},"result",[246,613,285],{"class":275},[246,615,328],{"class":275},[246,617,618],{"class":275}," {\n",[246,620,622,625,628,630,632,636],{"class":248,"line":621},6,[246,623,624],{"class":275},"    \"",[246,626,627],{"class":252},"overall_score",[246,629,285],{"class":275},[246,631,328],{"class":275},[246,633,635],{"class":634},"sbssI"," 7.4",[246,637,563],{"class":275},[246,639,641,643,646,648,650,653],{"class":248,"line":640},7,[246,642,624],{"class":275},[246,644,645],{"class":252},"dependency_number",[246,647,285],{"class":275},[246,649,328],{"class":275},[246,651,652],{"class":634}," 182",[246,654,563],{"class":275},[246,656,658,660,663,665,667,670,672,675,677,679,682,684,686,689,691,693,696,698,700,703,705,707,710,712,714,717,719,721,724],{"class":248,"line":657},8,[246,659,624],{"class":275},[246,661,662],{"class":252},"vulnerabilities_by_severity",[246,664,285],{"class":275},[246,666,328],{"class":275},[246,668,669],{"class":275}," {",[246,671,276],{"class":275},[246,673,674],{"class":634},"CRITICAL",[246,676,285],{"class":275},[246,678,328],{"class":275},[246,680,681],{"class":634}," 0",[246,683,338],{"class":275},[246,685,276],{"class":275},[246,687,688],{"class":634},"HIGH",[246,690,285],{"class":275},[246,692,328],{"class":275},[246,694,695],{"class":634}," 2",[246,697,338],{"class":275},[246,699,276],{"class":275},[246,701,702],{"class":634},"MODERATE",[246,704,285],{"class":275},[246,706,328],{"class":275},[246,708,709],{"class":634}," 5",[246,711,338],{"class":275},[246,713,276],{"class":275},[246,715,716],{"class":634},"LOW",[246,718,285],{"class":275},[246,720,328],{"class":275},[246,722,723],{"class":634}," 1",[246,725,726],{"class":275}," },\n",[246,728,730,732,735,737,739],{"class":248,"line":729},9,[246,731,624],{"class":275},[246,733,734],{"class":252},"commercial_use",[246,736,285],{"class":275},[246,738,328],{"class":275},[246,740,741],{"class":275}," false,\n",[246,743,745,747,750,752,754],{"class":248,"line":744},10,[246,746,624],{"class":275},[246,748,749],{"class":252},"direct_up_to_date",[246,751,285],{"class":275},[246,753,328],{"class":275},[246,755,756],{"class":634}," 84\n",[246,758,760],{"class":248,"line":759},11,[246,761,762],{"class":275},"  },\n",[246,764,766,768,771,773,775],{"class":248,"line":765},12,[246,767,293],{"class":275},[246,769,770],{"class":322},"error",[246,772,285],{"class":275},[246,774,328],{"class":275},[246,776,777],{"class":275}," null\n",[246,779,781],{"class":248,"line":780},13,[246,782,783],{"class":275},"}\n",[120,785,786,788,789,791,792,794,795,798,799,788,801,804,805,807],{},[124,787,491],{}," is ",[124,790,495],{},", ",[124,793,578],{}," or ",[124,796,797],{},"failed",". ",[124,800,611],{},[124,802,803],{},"null"," until the\nanalysis completes, and ",[124,806,770],{}," contains the reason when it fails, for example\nwhen the GitHub App no longer has access to the repository.",[120,809,810],{},"An analysis takes about ten minutes, and Deptools stops one at 60 minutes. That\nlimit is not the wait to write in your pipeline. The script below polls every 20\nseconds and gives up after 90 attempts, so 30 minutes, because a waiting job\nburns CI minutes. Giving up cancels nothing: the analysis keeps running on the\nDeptools side and its result reaches the dashboard. Raise the 90 attempts to 180\nto wait the full hour, or lower them to fail faster.",[120,812,813,814,816,817,328],{},"This script triggers the scan, skips a cooldown and waits for the result. It\nneeds ",[124,815,126],{}," and ",[124,818,819],{},"jq",[237,821,823],{"className":239,"code":822,"language":241,"meta":242,"style":242},"#!\u002Fbin\u002Fsh\nset -eu\n\napi=\"https:\u002F\u002Fapi.deptools.io\"\nauth=\"Authorization: Bearer $DEPTOOLS_API_KEY\"\n\n# ── Trigger ──────────────────────────────────────────────────────────────\ncode=$(curl -sS -o response.json -w '%{http_code}' -X POST -H \"$auth\" \\\n  \"$api\u002Fv1\u002Fprojects\u002F$DEPTOOLS_PROJECT_UUID\u002Fscan\")\n\nif [ \"$code\" = 429 ]; then\n  echo \"Scan cooldown active, retry after $(jq -r '.errors[0].retryAfter \u002F\u002F \"later\"' response.json). Skipping.\"\n  exit 0\nfi\nif [ \"$code\" != 202 ]; then\n  echo \"Scan refused (HTTP $code): $(jq -r '.errors[0].message' response.json)\" >&2\n  exit 1\nfi\n\njob=$(jq -r '.jobId' response.json)\necho \"Scan accepted, job $job\"\n\n# ── Wait, 30 minutes at most ─────────────────────────────────────────────\nattempt=0\nstatus=running\nwhile [ \"$attempt\" -lt 90 ]; do\n  sleep 20\n  attempt=$((attempt + 1))\n  curl -sS -o response.json -H \"$auth\" \"$api\u002Fv1\u002Fscans\u002F$job\u002Fstatus\"\n  status=$(jq -r '.status' response.json)\n  [ \"$status\" = running ] || break\ndone\n\ncase \"$status\" in\n  completed) ;;\n  failed)\n    echo \"Analysis failed: $(jq -r '.error' response.json)\" >&2\n    exit 1 ;;\n  *)\n    echo \"Timed out waiting for job $job, the analysis keeps running\" >&2\n    exit 1 ;;\nesac\n",[124,824,825,831,840,846,860,875,879,884,928,947,951,979,1014,1022,1028,1051,1087,1095,1100,1105,1129,1145,1150,1156,1167,1177,1203,1212,1231,1264,1287,1314,1320,1325,1340,1351,1359,1389,1399,1405,1424,1433],{"__ignoreMap":242},[246,826,827],{"class":248,"line":249},[246,828,830],{"class":829},"sHwdD","#!\u002Fbin\u002Fsh\n",[246,832,833,837],{"class":248,"line":269},[246,834,836],{"class":835},"s2Zo4","set",[246,838,839],{"class":255}," -eu\n",[246,841,842],{"class":248,"line":290},[246,843,845],{"emptyLinePlaceholder":844},true,"\n",[246,847,848,851,854,856,858],{"class":248,"line":585},[246,849,850],{"class":265},"api",[246,852,853],{"class":275},"=",[246,855,285],{"class":275},[246,857,370],{"class":255},[246,859,305],{"class":275},[246,861,862,865,867,869,871,873],{"class":248,"line":606},[246,863,864],{"class":265},"auth",[246,866,853],{"class":275},[246,868,285],{"class":275},[246,870,279],{"class":255},[246,872,282],{"class":265},[246,874,305],{"class":275},[246,876,877],{"class":248,"line":621},[246,878,845],{"emptyLinePlaceholder":844},[246,880,881],{"class":248,"line":640},[246,882,883],{"class":829},"# ── Trigger ──────────────────────────────────────────────────────────────\n",[246,885,886,888,891,893,895,898,901,904,907,910,913,915,917,919,921,924,926],{"class":248,"line":657},[246,887,124],{"class":265},[246,889,890],{"class":275},"=$(",[246,892,126],{"class":252},[246,894,256],{"class":255},[246,896,897],{"class":255}," -o",[246,899,900],{"class":255}," response.json",[246,902,903],{"class":255}," -w",[246,905,906],{"class":275}," '",[246,908,909],{"class":255},"%{http_code}",[246,911,912],{"class":275},"'",[246,914,259],{"class":255},[246,916,262],{"class":255},[246,918,509],{"class":255},[246,920,276],{"class":275},[246,922,923],{"class":265},"$auth",[246,925,285],{"class":275},[246,927,266],{"class":265},[246,929,930,932,935,938,940,942,944],{"class":248,"line":729},[246,931,293],{"class":275},[246,933,934],{"class":265},"$api",[246,936,937],{"class":255},"\u002Fv1\u002Fprojects\u002F",[246,939,299],{"class":265},[246,941,302],{"class":255},[246,943,285],{"class":275},[246,945,946],{"class":275},")\n",[246,948,949],{"class":248,"line":744},[246,950,845],{"emptyLinePlaceholder":844},[246,952,953,957,960,962,965,967,970,973,976],{"class":248,"line":759},[246,954,956],{"class":955},"s7zQu","if",[246,958,959],{"class":275}," [",[246,961,276],{"class":275},[246,963,964],{"class":265},"$code",[246,966,285],{"class":275},[246,968,969],{"class":275}," =",[246,971,972],{"class":634}," 429",[246,974,975],{"class":275}," ];",[246,977,978],{"class":955}," then\n",[246,980,981,984,986,989,992,994,997,999,1002,1004,1006,1009,1012],{"class":248,"line":765},[246,982,983],{"class":835},"  echo",[246,985,276],{"class":275},[246,987,988],{"class":255},"Scan cooldown active, retry after ",[246,990,991],{"class":275},"$(",[246,993,819],{"class":252},[246,995,996],{"class":255}," -r ",[246,998,912],{"class":275},[246,1000,1001],{"class":255},".errors[0].retryAfter \u002F\u002F \"later\"",[246,1003,912],{"class":275},[246,1005,900],{"class":255},[246,1007,1008],{"class":275},")",[246,1010,1011],{"class":255},". Skipping.",[246,1013,305],{"class":275},[246,1015,1016,1019],{"class":248,"line":780},[246,1017,1018],{"class":835},"  exit",[246,1020,1021],{"class":634}," 0\n",[246,1023,1025],{"class":248,"line":1024},14,[246,1026,1027],{"class":955},"fi\n",[246,1029,1031,1033,1035,1037,1039,1041,1044,1047,1049],{"class":248,"line":1030},15,[246,1032,956],{"class":955},[246,1034,959],{"class":275},[246,1036,276],{"class":275},[246,1038,964],{"class":265},[246,1040,285],{"class":275},[246,1042,1043],{"class":275}," !=",[246,1045,1046],{"class":634}," 202",[246,1048,975],{"class":275},[246,1050,978],{"class":955},[246,1052,1054,1056,1058,1061,1063,1066,1068,1070,1072,1074,1077,1079,1081,1084],{"class":248,"line":1053},16,[246,1055,983],{"class":835},[246,1057,276],{"class":275},[246,1059,1060],{"class":255},"Scan refused (HTTP ",[246,1062,964],{"class":265},[246,1064,1065],{"class":255},"): ",[246,1067,991],{"class":275},[246,1069,819],{"class":252},[246,1071,996],{"class":255},[246,1073,912],{"class":275},[246,1075,1076],{"class":255},".errors[0].message",[246,1078,912],{"class":275},[246,1080,900],{"class":255},[246,1082,1083],{"class":275},")\"",[246,1085,1086],{"class":275}," >&2\n",[246,1088,1090,1092],{"class":248,"line":1089},17,[246,1091,1018],{"class":835},[246,1093,1094],{"class":634}," 1\n",[246,1096,1098],{"class":248,"line":1097},18,[246,1099,1027],{"class":955},[246,1101,1103],{"class":248,"line":1102},19,[246,1104,845],{"emptyLinePlaceholder":844},[246,1106,1108,1111,1113,1115,1118,1120,1123,1125,1127],{"class":248,"line":1107},20,[246,1109,1110],{"class":265},"job",[246,1112,890],{"class":275},[246,1114,819],{"class":252},[246,1116,1117],{"class":255}," -r",[246,1119,906],{"class":275},[246,1121,1122],{"class":255},".jobId",[246,1124,912],{"class":275},[246,1126,900],{"class":255},[246,1128,946],{"class":275},[246,1130,1132,1135,1137,1140,1143],{"class":248,"line":1131},21,[246,1133,1134],{"class":835},"echo",[246,1136,276],{"class":275},[246,1138,1139],{"class":255},"Scan accepted, job ",[246,1141,1142],{"class":265},"$job",[246,1144,305],{"class":275},[246,1146,1148],{"class":248,"line":1147},22,[246,1149,845],{"emptyLinePlaceholder":844},[246,1151,1153],{"class":248,"line":1152},23,[246,1154,1155],{"class":829},"# ── Wait, 30 minutes at most ─────────────────────────────────────────────\n",[246,1157,1159,1162,1164],{"class":248,"line":1158},24,[246,1160,1161],{"class":265},"attempt",[246,1163,853],{"class":275},[246,1165,1166],{"class":255},"0\n",[246,1168,1170,1172,1174],{"class":248,"line":1169},25,[246,1171,491],{"class":265},[246,1173,853],{"class":275},[246,1175,1176],{"class":255},"running\n",[246,1178,1180,1183,1185,1187,1190,1192,1195,1198,1200],{"class":248,"line":1179},26,[246,1181,1182],{"class":955},"while",[246,1184,959],{"class":275},[246,1186,276],{"class":275},[246,1188,1189],{"class":265},"$attempt",[246,1191,285],{"class":275},[246,1193,1194],{"class":275}," -lt",[246,1196,1197],{"class":634}," 90",[246,1199,975],{"class":275},[246,1201,1202],{"class":955}," do\n",[246,1204,1206,1209],{"class":248,"line":1205},27,[246,1207,1208],{"class":252},"  sleep",[246,1210,1211],{"class":634}," 20\n",[246,1213,1215,1218,1221,1223,1226,1228],{"class":248,"line":1214},28,[246,1216,1217],{"class":265},"  attempt",[246,1219,1220],{"class":275},"=$((",[246,1222,1161],{"class":252},[246,1224,1225],{"class":255}," +",[246,1227,723],{"class":634},[246,1229,1230],{"class":275},"))\n",[246,1232,1234,1237,1239,1241,1243,1245,1247,1249,1251,1253,1255,1258,1260,1262],{"class":248,"line":1233},29,[246,1235,1236],{"class":252},"  curl",[246,1238,256],{"class":255},[246,1240,897],{"class":255},[246,1242,900],{"class":255},[246,1244,509],{"class":255},[246,1246,276],{"class":275},[246,1248,923],{"class":265},[246,1250,285],{"class":275},[246,1252,276],{"class":275},[246,1254,934],{"class":265},[246,1256,1257],{"class":255},"\u002Fv1\u002Fscans\u002F",[246,1259,1142],{"class":265},[246,1261,532],{"class":255},[246,1263,305],{"class":275},[246,1265,1267,1270,1272,1274,1276,1278,1281,1283,1285],{"class":248,"line":1266},30,[246,1268,1269],{"class":265},"  status",[246,1271,890],{"class":275},[246,1273,819],{"class":252},[246,1275,1117],{"class":255},[246,1277,906],{"class":275},[246,1279,1280],{"class":255},".status",[246,1282,912],{"class":275},[246,1284,900],{"class":255},[246,1286,946],{"class":275},[246,1288,1290,1293,1295,1298,1300,1302,1305,1308,1311],{"class":248,"line":1289},31,[246,1291,1292],{"class":275},"  [",[246,1294,276],{"class":275},[246,1296,1297],{"class":265},"$status",[246,1299,285],{"class":275},[246,1301,969],{"class":275},[246,1303,1304],{"class":265}," running ",[246,1306,1307],{"class":275},"]",[246,1309,1310],{"class":275}," ||",[246,1312,1313],{"class":955}," break\n",[246,1315,1317],{"class":248,"line":1316},32,[246,1318,1319],{"class":955},"done\n",[246,1321,1323],{"class":248,"line":1322},33,[246,1324,845],{"emptyLinePlaceholder":844},[246,1326,1328,1331,1333,1335,1337],{"class":248,"line":1327},34,[246,1329,1330],{"class":955},"case",[246,1332,276],{"class":275},[246,1334,1297],{"class":265},[246,1336,285],{"class":275},[246,1338,1339],{"class":955}," in\n",[246,1341,1343,1346,1348],{"class":248,"line":1342},35,[246,1344,1345],{"class":255},"  completed",[246,1347,1008],{"class":275},[246,1349,1350],{"class":275}," ;;\n",[246,1352,1354,1357],{"class":248,"line":1353},36,[246,1355,1356],{"class":255},"  failed",[246,1358,946],{"class":275},[246,1360,1362,1365,1367,1370,1372,1374,1376,1378,1381,1383,1385,1387],{"class":248,"line":1361},37,[246,1363,1364],{"class":835},"    echo",[246,1366,276],{"class":275},[246,1368,1369],{"class":255},"Analysis failed: ",[246,1371,991],{"class":275},[246,1373,819],{"class":252},[246,1375,996],{"class":255},[246,1377,912],{"class":275},[246,1379,1380],{"class":255},".error",[246,1382,912],{"class":275},[246,1384,900],{"class":255},[246,1386,1083],{"class":275},[246,1388,1086],{"class":275},[246,1390,1392,1395,1397],{"class":248,"line":1391},38,[246,1393,1394],{"class":835},"    exit",[246,1396,723],{"class":634},[246,1398,1350],{"class":275},[246,1400,1402],{"class":248,"line":1401},39,[246,1403,1404],{"class":275},"  *)\n",[246,1406,1408,1410,1412,1415,1417,1420,1422],{"class":248,"line":1407},40,[246,1409,1364],{"class":835},[246,1411,276],{"class":275},[246,1413,1414],{"class":255},"Timed out waiting for job ",[246,1416,1142],{"class":265},[246,1418,1419],{"class":255},", the analysis keeps running",[246,1421,285],{"class":275},[246,1423,1086],{"class":275},[246,1425,1427,1429,1431],{"class":248,"line":1426},41,[246,1428,1394],{"class":835},[246,1430,723],{"class":634},[246,1432,1350],{"class":275},[246,1434,1436],{"class":248,"line":1435},42,[246,1437,1438],{"class":955},"esac\n",[153,1440,1442],{"id":1441},"gate-the-build","Gate the build",[120,1444,1445,1446,1449,1450,1453,1454,1456],{},"The rest of the same file turns the result into gates. ",[124,1447,1448],{},"response.json"," now holds\nthe finished analysis, so each ",[124,1451,1452],{},"gate"," line is one ",[124,1455,819],{}," condition on it. The first\none that fails stops the job:",[237,1458,1460],{"className":239,"code":1459,"language":241,"meta":242,"style":242},"# ── Quality gates ────────────────────────────────────────────────────────\ngate() {\n  jq -e \"$1\" response.json > \u002Fdev\u002Fnull || {\n    echo \"Gate failed: $2\" >&2\n    exit 1\n  }\n}\n\ngate '.result.vulnerabilities_by_severity | .CRITICAL + .HIGH == 0' \\\n  \"at least one HIGH or CRITICAL vulnerability\"\ngate '.result.overall_score >= 7' \"health score below 7\"\ngate '.result.commercial_use == false' \"strong copyleft license found\"\ngate '.result.direct_up_to_date >= 80' \"less than 80% of direct dependencies up to date\"\n\necho \"All gates passed, score $(jq -r '.result.overall_score' response.json)\u002F10\"\n",[124,1461,1462,1467,1476,1504,1520,1526,1531,1535,1539,1552,1561,1579,1597,1615,1619],{"__ignoreMap":242},[246,1463,1464],{"class":248,"line":249},[246,1465,1466],{"class":829},"# ── Quality gates ────────────────────────────────────────────────────────\n",[246,1468,1469,1471,1474],{"class":248,"line":269},[246,1470,1452],{"class":835},[246,1472,1473],{"class":275},"()",[246,1475,618],{"class":275},[246,1477,1478,1481,1484,1486,1490,1492,1494,1497,1500,1502],{"class":248,"line":290},[246,1479,1480],{"class":252},"  jq",[246,1482,1483],{"class":255}," -e",[246,1485,276],{"class":275},[246,1487,1489],{"class":1488},"sHdIc","$1",[246,1491,285],{"class":275},[246,1493,900],{"class":255},[246,1495,1496],{"class":275}," >",[246,1498,1499],{"class":255}," \u002Fdev\u002Fnull",[246,1501,1310],{"class":275},[246,1503,618],{"class":275},[246,1505,1506,1508,1510,1513,1516,1518],{"class":248,"line":585},[246,1507,1364],{"class":835},[246,1509,276],{"class":275},[246,1511,1512],{"class":255},"Gate failed: ",[246,1514,1515],{"class":1488},"$2",[246,1517,285],{"class":275},[246,1519,1086],{"class":275},[246,1521,1522,1524],{"class":248,"line":606},[246,1523,1394],{"class":835},[246,1525,1094],{"class":634},[246,1527,1528],{"class":248,"line":621},[246,1529,1530],{"class":275},"  }\n",[246,1532,1533],{"class":248,"line":640},[246,1534,783],{"class":275},[246,1536,1537],{"class":248,"line":657},[246,1538,845],{"emptyLinePlaceholder":844},[246,1540,1541,1543,1545,1548,1550],{"class":248,"line":729},[246,1542,1452],{"class":252},[246,1544,906],{"class":275},[246,1546,1547],{"class":255},".result.vulnerabilities_by_severity | .CRITICAL + .HIGH == 0",[246,1549,912],{"class":275},[246,1551,266],{"class":265},[246,1553,1554,1556,1559],{"class":248,"line":744},[246,1555,293],{"class":275},[246,1557,1558],{"class":255},"at least one HIGH or CRITICAL vulnerability",[246,1560,305],{"class":275},[246,1562,1563,1565,1567,1570,1572,1574,1577],{"class":248,"line":759},[246,1564,1452],{"class":252},[246,1566,906],{"class":275},[246,1568,1569],{"class":255},".result.overall_score >= 7",[246,1571,912],{"class":275},[246,1573,276],{"class":275},[246,1575,1576],{"class":255},"health score below 7",[246,1578,305],{"class":275},[246,1580,1581,1583,1585,1588,1590,1592,1595],{"class":248,"line":765},[246,1582,1452],{"class":252},[246,1584,906],{"class":275},[246,1586,1587],{"class":255},".result.commercial_use == false",[246,1589,912],{"class":275},[246,1591,276],{"class":275},[246,1593,1594],{"class":255},"strong copyleft license found",[246,1596,305],{"class":275},[246,1598,1599,1601,1603,1606,1608,1610,1613],{"class":248,"line":780},[246,1600,1452],{"class":252},[246,1602,906],{"class":275},[246,1604,1605],{"class":255},".result.direct_up_to_date >= 80",[246,1607,912],{"class":275},[246,1609,276],{"class":275},[246,1611,1612],{"class":255},"less than 80% of direct dependencies up to date",[246,1614,305],{"class":275},[246,1616,1617],{"class":248,"line":1024},[246,1618,845],{"emptyLinePlaceholder":844},[246,1620,1621,1623,1625,1628,1630,1632,1634,1636,1639,1641,1643,1645,1648],{"class":248,"line":1030},[246,1622,1134],{"class":835},[246,1624,276],{"class":275},[246,1626,1627],{"class":255},"All gates passed, score ",[246,1629,991],{"class":275},[246,1631,819],{"class":252},[246,1633,996],{"class":255},[246,1635,912],{"class":275},[246,1637,1638],{"class":255},".result.overall_score",[246,1640,912],{"class":275},[246,1642,900],{"class":255},[246,1644,1008],{"class":275},[246,1646,1647],{"class":255},"\u002F10",[246,1649,305],{"class":275},[120,1651,1652],{},"Keep the conditions you want, in the order you want them evaluated, and drop the\nothers.",[468,1654,1655,1657,1658,1661,1662,1664],{},[124,1656,734],{}," reads backwards. ",[124,1659,1660],{},"true"," does not mean commercial use is\nallowed. It means the analysis found at least one strong copyleft license, which\nis the case you want to look at.\n",[129,1663,95],{"href":96}," explains what strong copyleft\nimplies.",[120,1666,1667,1668,1670,1671,1673,1674,1676,1677,788,1679,1681,1682,1684],{},"Two fields can be ",[124,1669,803],{},", and a comparison against ",[124,1672,803],{}," is false in ",[124,1675,819],{},", so\nthe gate fails. ",[124,1678,749],{},[124,1680,803],{}," when the project has no direct\ndependency, ",[124,1683,627],{}," when the analysis produced no score. Neither means your dependencies are unhealthy. So guard the value if you would rather\nskip the gate than break the build:",[237,1686,1688],{"className":239,"code":1687,"language":241,"meta":242,"style":242},"gate '.result.direct_up_to_date == null or .result.direct_up_to_date >= 80' \\\n  \"less than 80% of direct dependencies up to date\"\n",[124,1689,1690,1703],{"__ignoreMap":242},[246,1691,1692,1694,1696,1699,1701],{"class":248,"line":249},[246,1693,1452],{"class":252},[246,1695,906],{"class":275},[246,1697,1698],{"class":255},".result.direct_up_to_date == null or .result.direct_up_to_date >= 80",[246,1700,912],{"class":275},[246,1702,266],{"class":265},[246,1704,1705,1707,1709],{"class":248,"line":269},[246,1706,293],{"class":275},[246,1708,1612],{"class":255},[246,1710,305],{"class":275},[1712,1713,1714],"tip",{},"Start with one gate the project passes today, HIGH and CRITICAL vulnerabilities\nfor example, then tighten. A pipeline that fails on its first run gets disabled\nby the team rather than read.",[153,1716,1718],{"id":1717},"gitlab-ci-jenkins-and-others","GitLab CI, Jenkins and others",[120,1720,1721,1722,1725],{},"Commit the two blocks above as one file, ",[124,1723,1724],{},"deptools-gate.sh",", then call it from\none job. Nothing in it is specific to a CI product.",[1727,1728,1729,1819,1915],"code-group",{},[237,1730,1735],{"className":1731,"code":1732,"filename":1733,"language":1734,"meta":242,"style":242},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","deptools-scan:\n  stage: test\n  image: alpine:3.20\n  before_script:\n    - apk add --no-cache curl jq\n  script:\n    - sh deptools-gate.sh\n  rules:\n    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'\n",".gitlab-ci.yml","yaml",[124,1736,1737,1746,1756,1766,1773,1781,1788,1795,1802],{"__ignoreMap":242},[246,1738,1739,1743],{"class":248,"line":249},[246,1740,1742],{"class":1741},"swJcz","deptools-scan",[246,1744,1745],{"class":275},":\n",[246,1747,1748,1751,1753],{"class":248,"line":269},[246,1749,1750],{"class":1741},"  stage",[246,1752,328],{"class":275},[246,1754,1755],{"class":255}," test\n",[246,1757,1758,1761,1763],{"class":248,"line":290},[246,1759,1760],{"class":1741},"  image",[246,1762,328],{"class":275},[246,1764,1765],{"class":255}," alpine:3.20\n",[246,1767,1768,1771],{"class":248,"line":585},[246,1769,1770],{"class":1741},"  before_script",[246,1772,1745],{"class":275},[246,1774,1775,1778],{"class":248,"line":606},[246,1776,1777],{"class":275},"    -",[246,1779,1780],{"class":255}," apk add --no-cache curl jq\n",[246,1782,1783,1786],{"class":248,"line":621},[246,1784,1785],{"class":1741},"  script",[246,1787,1745],{"class":275},[246,1789,1790,1792],{"class":248,"line":640},[246,1791,1777],{"class":275},[246,1793,1794],{"class":255}," sh deptools-gate.sh\n",[246,1796,1797,1800],{"class":248,"line":657},[246,1798,1799],{"class":1741},"  rules",[246,1801,1745],{"class":275},[246,1803,1804,1806,1809,1811,1813,1816],{"class":248,"line":729},[246,1805,1777],{"class":275},[246,1807,1808],{"class":1741}," if",[246,1810,328],{"class":275},[246,1812,906],{"class":275},[246,1814,1815],{"class":255},"$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH",[246,1817,1818],{"class":275},"'\n",[237,1820,1825],{"className":1821,"code":1822,"filename":1823,"language":1824,"meta":242,"style":242},"language-groovy shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","stage('Deptools scan') {\n  environment {\n    DEPTOOLS_API_KEY = credentials('deptools-api-key')\n    DEPTOOLS_PROJECT_UUID = 'your-project-uuid'\n  }\n  steps {\n    sh 'sh deptools-gate.sh'\n  }\n}\n","Jenkinsfile","groovy",[124,1826,1827,1846,1851,1872,1886,1890,1895,1907,1911],{"__ignoreMap":242},[246,1828,1829,1832,1835,1837,1840,1842,1844],{"class":248,"line":249},[246,1830,1831],{"class":265},"stage",[246,1833,1834],{"class":275},"(",[246,1836,912],{"class":275},[246,1838,1839],{"class":255},"Deptools scan",[246,1841,912],{"class":275},[246,1843,1008],{"class":275},[246,1845,618],{"class":265},[246,1847,1848],{"class":248,"line":269},[246,1849,1850],{"class":265},"  environment {\n",[246,1852,1853,1856,1858,1861,1863,1865,1868,1870],{"class":248,"line":290},[246,1854,1855],{"class":265},"    DEPTOOLS_API_KEY ",[246,1857,853],{"class":275},[246,1859,1860],{"class":265}," credentials",[246,1862,1834],{"class":275},[246,1864,912],{"class":275},[246,1866,1867],{"class":255},"deptools-api-key",[246,1869,912],{"class":275},[246,1871,946],{"class":275},[246,1873,1874,1877,1879,1881,1884],{"class":248,"line":585},[246,1875,1876],{"class":265},"    DEPTOOLS_PROJECT_UUID ",[246,1878,853],{"class":275},[246,1880,906],{"class":275},[246,1882,1883],{"class":255},"your-project-uuid",[246,1885,1818],{"class":275},[246,1887,1888],{"class":248,"line":606},[246,1889,1530],{"class":265},[246,1891,1892],{"class":248,"line":621},[246,1893,1894],{"class":265},"  steps {\n",[246,1896,1897,1900,1902,1905],{"class":248,"line":640},[246,1898,1899],{"class":265},"    sh ",[246,1901,912],{"class":275},[246,1903,1904],{"class":255},"sh deptools-gate.sh",[246,1906,1818],{"class":275},[246,1908,1909],{"class":248,"line":657},[246,1910,1530],{"class":265},[246,1912,1913],{"class":248,"line":729},[246,1914,783],{"class":265},[237,1916,1919],{"className":1731,"code":1917,"filename":1918,"language":1734,"meta":242,"style":242},"pipelines:\n  branches:\n    main:\n      - step:\n          name: Deptools scan\n          image: alpine:3.20\n          script:\n            - apk add --no-cache curl jq\n            - sh deptools-gate.sh\n","bitbucket-pipelines.yml",[124,1920,1921,1928,1935,1942,1952,1962,1971,1978,1985],{"__ignoreMap":242},[246,1922,1923,1926],{"class":248,"line":249},[246,1924,1925],{"class":1741},"pipelines",[246,1927,1745],{"class":275},[246,1929,1930,1933],{"class":248,"line":269},[246,1931,1932],{"class":1741},"  branches",[246,1934,1745],{"class":275},[246,1936,1937,1940],{"class":248,"line":290},[246,1938,1939],{"class":1741},"    main",[246,1941,1745],{"class":275},[246,1943,1944,1947,1950],{"class":248,"line":585},[246,1945,1946],{"class":275},"      -",[246,1948,1949],{"class":1741}," step",[246,1951,1745],{"class":275},[246,1953,1954,1957,1959],{"class":248,"line":606},[246,1955,1956],{"class":1741},"          name",[246,1958,328],{"class":275},[246,1960,1961],{"class":255}," Deptools scan\n",[246,1963,1964,1967,1969],{"class":248,"line":621},[246,1965,1966],{"class":1741},"          image",[246,1968,328],{"class":275},[246,1970,1765],{"class":255},[246,1972,1973,1976],{"class":248,"line":640},[246,1974,1975],{"class":1741},"          script",[246,1977,1745],{"class":275},[246,1979,1980,1983],{"class":248,"line":657},[246,1981,1982],{"class":275},"            -",[246,1984,1780],{"class":255},[246,1986,1987,1989],{"class":248,"line":729},[246,1988,1982],{"class":275},[246,1990,1794],{"class":255},[120,1992,1993,1994,1996,1997,1999],{},"Declare ",[124,1995,200],{}," as a masked variable, and ",[124,1998,190],{},"\nas an ordinary one, since it only names a project. On GitLab, store an organization key as a group variable so every project in the group can use it.",[120,2001,2002],{},"Run the job on a push to the branch the project analyzes, or on a schedule. A\nscan started from a merge request pipeline analyzes the branch of the project\nanyway, so it reports on code your merge request has not changed.",[120,2004,2005],{},"Runners hosted by your CI provider rarely reach the hourly limit of the scan\nendpoint. A fleet of self hosted runners behind one IP address can.",[153,2007,2009],{"id":2008},"trigger-a-scan-versus-push-your-build-files","Trigger a scan versus push your build files",[120,2011,2012],{},"Two different requests reach the same URL, and which one to use depends on\nwhether Deptools can read your repository.",[165,2014,2015,2028],{},[168,2016,2017],{},[171,2018,2019,2022,2025],{},[174,2020,2021],{},"Your setup",[174,2023,2024],{},"What your pipeline sends",[174,2026,2027],{},"Plan",[181,2029,2030,2045,2059],{},[171,2031,2032,2035,2042],{},[186,2033,2034],{},"GitHub repository, GitHub Actions",[186,2036,2037,2038,2041],{},"nothing, the ",[129,2039,2040],{"href":49},"action"," calls the API for you",[186,2043,2044],{},"any",[171,2046,2047,2050,2057],{},[186,2048,2049],{},"GitHub repository, any other pipeline",[186,2051,2052,2053,2056],{},"an empty ",[124,2054,2055],{},"POST",", this page",[186,2058,2044],{},[171,2060,2061,2064,2073],{},[186,2062,2063],{},"No repository Deptools can read",[186,2065,2066,2067,2070,2071],{},"a ",[124,2068,2069],{},"tar.gz"," of your build files, ",[129,2072,38],{"href":39},[186,2074,2075],{},"Pro",[120,2077,2078,2079,2081,2082,2084],{},"The difference is the body. A bare ",[124,2080,2055],{}," tells Deptools to read the build file\nitself, which it can only do on a repository the GitHub App reaches. A multipart\n",[124,2083,2055],{}," carries the files, which is the only thing an upload project accepts,\nsince Deptools has no way to fetch them.",[120,2086,2087],{},"Deptools refuses the wrong one, and the error names the mismatch:",[2089,2090,2091,2102],"ul",{},[2092,2093,2094,2095,2097,2098,2101],"li",{},"A bare ",[124,2096,2055],{}," on an upload project returns ",[124,2099,2100],{},"400 BUNDLE_REQUIRED",".",[2092,2103,2104,2105,2107,2108,2101],{},"A multipart ",[124,2106,2055],{}," on a project linked to a repository returns\n",[124,2109,2110],{},"422 UPLOAD_NOT_SUPPORTED_FOR_GIT_PROJECTS",[120,2112,2113],{},"Everything after the scan is identical in the three cases: the same analysis,\nthe same graph, the same score, and the same status endpoint to poll.",[153,2115,2117],{"id":2116},"next-steps","Next steps",[2089,2119,2120,2125],{},[2092,2121,2122,2124],{},[129,2123,59],{"href":60}," to set an expiration and rotate a\nkey without breaking a pipeline.",[2092,2126,2127,2129],{},[129,2128,48],{"href":49}," when a repository\nis on GitHub and the action can do the same work for you.",[2131,2132,2133],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":242,"searchDepth":269,"depth":269,"links":2135},[2136,2137,2138,2139,2140,2141],{"id":155,"depth":269,"text":156},{"id":484,"depth":269,"text":485},{"id":1441,"depth":269,"text":1442},{"id":1717,"depth":269,"text":1718},{"id":2008,"depth":269,"text":2009},{"id":2116,"depth":269,"text":2117},"Trigger and poll a scan with curl from GitLab CI, Jenkins or any other pipeline.","md",null,{},{"icon":57,"group":52},{"title":54,"description":2142},"nQuRRuOVAGiq90Puk6uobZxIKEtCWeLkfhlXC0EV4cY",[2150,2152],{"title":48,"path":49,"stem":50,"description":2151,"icon":51,"group":52,"children":-1},"Add the Deptools action to a workflow and fail the build when quality gates are not met.",{"title":59,"path":60,"stem":61,"description":2153,"icon":62,"group":52,"children":-1},"Create, store and revoke the project and organization keys used by your pipelines.",1787263157238]