mirror of
https://github.com/github/codeql.git
synced 2026-01-06 19:20:25 +01:00
Merge branch 'master' into steps
This commit is contained in:
1
.github/action/.gitignore
vendored
Normal file
1
.github/action/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
30718
.github/action/dist/index.js
vendored
Normal file
30718
.github/action/dist/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
175
.github/action/dist/licenses.txt
vendored
Normal file
175
.github/action/dist/licenses.txt
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
@actions/core
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/exec
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/http-client
|
||||
MIT
|
||||
Actions Http Client for Node.js
|
||||
|
||||
Copyright (c) GitHub, Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@actions/io
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/tool-cache
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@fastify/busboy
|
||||
MIT
|
||||
Copyright Brian White. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
semver
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
tunnel
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 Koichi Kobayashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
undici
|
||||
MIT
|
||||
MIT License
|
||||
|
||||
Copyright (c) Matteo Collina and Undici contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
uuid
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
639
.github/action/package-lock.json
generated
vendored
Normal file
639
.github/action/package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,639 @@
|
||||
{
|
||||
"name": "codeql-actions-action",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codeql-actions-action",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@actions/tool-cache": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.6.0",
|
||||
"@vercel/ncc": "^0.38.0",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
|
||||
"integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"dependencies": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/github": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
|
||||
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@octokit/core": "^3.6.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz",
|
||||
"integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"node_modules/@actions/tool-cache": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz",
|
||||
"integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.6",
|
||||
"@actions/exec": "^1.0.0",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/io": "^1.1.1",
|
||||
"semver": "^6.1.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/tool-cache/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
|
||||
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.3",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "12.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
|
||||
"integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "2.21.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
|
||||
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.40.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=2"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
|
||||
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.39.0",
|
||||
"deprecation": "^2.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
|
||||
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
|
||||
"integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^12.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.11.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz",
|
||||
"integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.38.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz",
|
||||
"integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.28.3",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
|
||||
"integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
||||
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
|
||||
"integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"requires": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"@actions/github": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
|
||||
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@octokit/core": "^3.6.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
||||
}
|
||||
},
|
||||
"@actions/http-client": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz",
|
||||
"integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"@actions/tool-cache": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz",
|
||||
"integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==",
|
||||
"requires": {
|
||||
"@actions/core": "^1.2.6",
|
||||
"@actions/exec": "^1.0.0",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/io": "^1.1.1",
|
||||
"semver": "^6.1.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fastify/busboy": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
|
||||
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA=="
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.3",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"requires": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "12.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
|
||||
"integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.21.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
|
||||
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.40.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
|
||||
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.39.0",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
|
||||
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "6.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
|
||||
"integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^12.11.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.11.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz",
|
||||
"integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"@vercel/ncc": {
|
||||
"version": "0.38.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz",
|
||||
"integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==",
|
||||
"dev": true
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
||||
"dev": true
|
||||
},
|
||||
"undici": {
|
||||
"version": "5.28.3",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
|
||||
"integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
|
||||
"requires": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
||||
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
48
.github/action/package.json
vendored
Normal file
48
.github/action/package.json
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "codeql-actions-action",
|
||||
"version": "0.1.0",
|
||||
"description": "CodeQL Pack to analyze GitHub Actions and Workflows",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"bundle": "npm run format:write && npm run package",
|
||||
"cli": "ts-node src/index.ts",
|
||||
"ci-test": "jest",
|
||||
"format:write": "prettier --write **/*.ts",
|
||||
"format:check": "prettier --check **/*.ts",
|
||||
"lint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
|
||||
"package": "ncc build src/index.ts --license licenses.txt",
|
||||
"package:watch": "npm run package -- --watch",
|
||||
"test": "(jest && make-coverage-badge --output-path ./badges/coverage.svg) || make-coverage-badge --output-path ./badges/coverage.svg",
|
||||
"all": "npm run format:write && npm run lint && npm run test && npm run package"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/GitHubSecurityLab/codeql-actions.git"
|
||||
},
|
||||
"exports": {
|
||||
".": "./dist/index.js"
|
||||
},
|
||||
"keywords": [
|
||||
"codeql",
|
||||
"security",
|
||||
"actions"
|
||||
],
|
||||
"author": "Pwntester",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/GitHubSecurityLab/codeql-actions/issues"
|
||||
},
|
||||
"homepage": "https://github.com/GitHubSecurityLab/codeql-actions#readme",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@actions/tool-cache": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.6.0",
|
||||
"@vercel/ncc": "^0.38.0",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
164
.github/action/src/codeql.ts
vendored
Normal file
164
.github/action/src/codeql.ts
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||
|
||||
export interface CodeQLConfig {
|
||||
// The path to the codeql bundle.
|
||||
path: string;
|
||||
// The language to use for analysis.
|
||||
language: string;
|
||||
// CodeQL pack to use for analysis.
|
||||
pack: string;
|
||||
// The codeql suite to use for analysis.
|
||||
suite: string;
|
||||
// The source root to use for analysis.
|
||||
source_root?: string;
|
||||
// The output file for the SARIF file.
|
||||
output?: string;
|
||||
}
|
||||
|
||||
export async function newCodeQL(): Promise<CodeQLConfig> {
|
||||
return {
|
||||
language: "yaml",
|
||||
path: await findCodeQL(),
|
||||
pack: "githubsecuritylab/actions-queries",
|
||||
suite: "codeql-suites/actions-code-scanning.qls",
|
||||
source_root: core.getInput("source-root"),
|
||||
output: core.getInput("sarif"),
|
||||
};
|
||||
}
|
||||
|
||||
export async function runCommand(
|
||||
config: CodeQLConfig,
|
||||
args: string[],
|
||||
cwd_arg?: string,
|
||||
): Promise<any> {
|
||||
var bin = path.join(config.path, "codeql");
|
||||
let output = "";
|
||||
var cwd: string = process.cwd();
|
||||
if (cwd_arg) {
|
||||
cwd = cwd_arg;
|
||||
}
|
||||
core.info("Current working directory: " + cwd);
|
||||
var options = {
|
||||
cwd: cwd,
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
output += data.toString();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await new toolrunner.ToolRunner(bin, args, options).exec();
|
||||
core.debug(`Finished running command :: ${bin} ${args.join(" ")}`);
|
||||
|
||||
return output.trim();
|
||||
}
|
||||
|
||||
export async function runCommandJson(
|
||||
config: CodeQLConfig,
|
||||
args: string[],
|
||||
): Promise<object> {
|
||||
return JSON.parse(await runCommand(config, args));
|
||||
}
|
||||
async function findCodeQL(): Promise<string> {
|
||||
// check if codeql is in the toolcache
|
||||
var codeqlPath = await findCodeQlInToolcache();
|
||||
if (codeqlPath !== undefined) {
|
||||
return codeqlPath;
|
||||
}
|
||||
// default to the codeql in the path
|
||||
return "codeql";
|
||||
}
|
||||
|
||||
async function findCodeQlInToolcache(): Promise<string | undefined> {
|
||||
const candidates = toolcache
|
||||
.findAllVersions("CodeQL")
|
||||
.map((version) => ({
|
||||
folder: toolcache.find("CodeQL", version),
|
||||
version,
|
||||
}))
|
||||
.filter(({ folder }) => fs.existsSync(path.join(folder, "pinned-version")));
|
||||
|
||||
if (candidates.length === 1) {
|
||||
const candidate = candidates[0];
|
||||
core.info(`CodeQL tools found in toolcache: '${candidate.folder}'.`);
|
||||
core.debug(`CodeQL toolcache version: '${candidate.version}'.`);
|
||||
|
||||
return path.join(candidate.folder, "codeql");
|
||||
}
|
||||
|
||||
core.warning(`No CodeQL tools found in toolcache.`);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function downloadPack(codeql: CodeQLConfig): Promise<boolean> {
|
||||
try {
|
||||
await runCommand(codeql, ["pack", "download", codeql.pack]);
|
||||
return true;
|
||||
} catch (error) {
|
||||
core.warning("Failed to download pack from GitHub...");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function codeqlDatabaseCreate(
|
||||
codeql: CodeQLConfig,
|
||||
): Promise<string> {
|
||||
// get runner temp directory for database
|
||||
var temp = process.env["RUNNER_TEMP"];
|
||||
if (temp === undefined) {
|
||||
temp = "/tmp";
|
||||
}
|
||||
var database_path = path.join(temp, "codeql-actions-db");
|
||||
var source_root =
|
||||
codeql.source_root || process.env["GITHUB_WORKSPACE"] || "./";
|
||||
|
||||
await runCommand(codeql, [
|
||||
"database",
|
||||
"create",
|
||||
"--language",
|
||||
codeql.language,
|
||||
"--source-root",
|
||||
source_root,
|
||||
database_path,
|
||||
]);
|
||||
|
||||
return database_path;
|
||||
}
|
||||
|
||||
export async function codeqlDatabaseAnalyze(
|
||||
codeql: CodeQLConfig,
|
||||
database_path: string,
|
||||
): Promise<string> {
|
||||
var codeql_output = codeql.output || "codeql-actions.sarif";
|
||||
|
||||
var cmd = [
|
||||
"database",
|
||||
"analyze",
|
||||
"--format",
|
||||
"sarif-latest",
|
||||
"--sarif-add-query-help",
|
||||
"--output",
|
||||
codeql_output,
|
||||
];
|
||||
|
||||
// remote pack or local pack
|
||||
if (codeql.pack.startsWith("githubsecuritylab/")) {
|
||||
var suite = codeql.pack + ":" + codeql.suite;
|
||||
} else {
|
||||
// assume path
|
||||
var suite = path.join(codeql.pack, codeql.suite);
|
||||
cmd.push("--search-path", codeql.pack);
|
||||
}
|
||||
|
||||
cmd.push(database_path, suite);
|
||||
|
||||
await runCommand(codeql, cmd);
|
||||
|
||||
return codeql_output;
|
||||
}
|
||||
61
.github/action/src/index.ts
vendored
Normal file
61
.github/action/src/index.ts
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as path from "path";
|
||||
import * as core from "@actions/core";
|
||||
import * as cql from "./codeql";
|
||||
|
||||
/**
|
||||
* The main function for the action.
|
||||
* @returns {Promise<void>} Resolves when the action is complete.
|
||||
*/
|
||||
export async function run(): Promise<void> {
|
||||
try {
|
||||
// set up codeql
|
||||
var codeql = await cql.newCodeQL();
|
||||
|
||||
core.debug(`CodeQL CLI found at '${codeql.path}'`);
|
||||
|
||||
await cql.runCommand(codeql, ["version", "--format", "terse"]);
|
||||
|
||||
// check yaml support
|
||||
var languages = await cql.runCommandJson(codeql, [
|
||||
"resolve",
|
||||
"languages",
|
||||
"--format",
|
||||
"json",
|
||||
]);
|
||||
|
||||
if (!languages.hasOwnProperty("yaml")) {
|
||||
core.setFailed("CodeQL Yaml extractor not installed");
|
||||
throw new Error("CodeQL Yaml extractor not installed");
|
||||
}
|
||||
|
||||
// download pack
|
||||
core.info(`Downloading CodeQL Actions pack '${codeql.pack}'`);
|
||||
var pack_downloaded = await cql.downloadPack(codeql);
|
||||
|
||||
if (pack_downloaded === false) {
|
||||
var action_path = path.resolve(path.join(__dirname, "..", "..", ".."));
|
||||
codeql.pack = path.join(action_path, "ql", "src");
|
||||
|
||||
core.info(`Pack defaulting back to local pack: '${codeql.pack}'`);
|
||||
} else {
|
||||
core.info(`Pack downloaded '${codeql.pack}'`);
|
||||
}
|
||||
|
||||
core.info("Creating CodeQL database...");
|
||||
var database_path = await cql.codeqlDatabaseCreate(codeql);
|
||||
|
||||
core.info("Running CodeQL analysis...");
|
||||
var sarif = await cql.codeqlDatabaseAnalyze(codeql, database_path);
|
||||
|
||||
core.info(`SARIF results: '${sarif}'`);
|
||||
core.setOutput("sarif", sarif);
|
||||
|
||||
core.info("Finished CodeQL analysis");
|
||||
} catch (error) {
|
||||
// Fail the workflow run if an error occurs
|
||||
if (error instanceof Error) core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
run();
|
||||
24
.github/action/tsconfig.json
vendored
Normal file
24
.github/action/tsconfig.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"rootDir": "./src",
|
||||
"moduleResolution": "NodeNext",
|
||||
"baseUrl": "./",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"noImplicitAny": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"newLine": "lf"
|
||||
},
|
||||
"exclude": [
|
||||
"./dist",
|
||||
"./node_modules",
|
||||
"./__tests__",
|
||||
"./coverage"
|
||||
]
|
||||
}
|
||||
28
.github/workflows/build.yml
vendored
Normal file
28
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Build and Compile Action
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: ["master", "develop"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
src:
|
||||
- '.github/action/**'
|
||||
- 'action.yml'
|
||||
|
||||
- name: Run action
|
||||
if: steps.changes.outputs.src == 'true'
|
||||
uses: ./
|
||||
31
.github/workflows/copy-to-bughalla.yml
vendored
Normal file
31
.github/workflows/copy-to-bughalla.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Copy to Bughalla
|
||||
|
||||
on: push
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
copy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.BUGHALLA_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- run: |
|
||||
rm -rf .github/workflows/copy-to-bughalla.yml
|
||||
git remote set-url --push origin git@github.com:bughalla/codeql-actions
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add -v .
|
||||
git commit -m 'Actions: Add patch'
|
||||
|
||||
- name: Push changes
|
||||
uses: ad-m/github-push-action@35284cf030a5836cb567a7bf1b39ebafbfae5f4a
|
||||
with:
|
||||
repository: bughalla/codeql-actions
|
||||
github_token: ${{ secrets.BUGHALLA_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
force: true
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
.DS_Store
|
||||
**/*.testproj
|
||||
ql/lib/.codeql/
|
||||
ql/src/.codeql/
|
||||
|
||||
25
action.yml
Normal file
25
action.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: "codeql-actions"
|
||||
description: "CodeQL Pack for GitHub Actions and Workflows"
|
||||
|
||||
inputs:
|
||||
token:
|
||||
description: GitHub Token
|
||||
default: ${{ github.token }}
|
||||
|
||||
source-root:
|
||||
description: "Path of the root source code directory, relative to $GITHUB_WORKSPACE."
|
||||
default: ${{ github.workspace }}
|
||||
|
||||
sarif-output:
|
||||
description: "SARIF File Output"
|
||||
default: "codeql-actions.sarif"
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Do something with context
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
node ${{ github.action_path }}/.github/action/dist/index.js
|
||||
@@ -95,6 +95,8 @@ class OutputsStmt extends Statement instanceof YamlMapping {
|
||||
this.(YamlMapping).lookup(name).(YamlMapping).lookup("value") = result or
|
||||
this.(YamlMapping).lookup(name) = result
|
||||
}
|
||||
|
||||
string getAnOutputName() { this.(YamlMapping).maps(any(YamlString s | s.getValue() = result), _) }
|
||||
}
|
||||
|
||||
class InputExpr extends Expression instanceof YamlString {
|
||||
@@ -147,7 +149,7 @@ class JobStmt extends Statement instanceof Actions::Job {
|
||||
* out1: ${steps.foo.bar}
|
||||
* out2: ${steps.foo.baz}
|
||||
*/
|
||||
JobOutputStmt getOutputStmt() { result = this.(Actions::Job).lookup("outputs") }
|
||||
OutputsStmt getOutputsStmt() { result = this.(Actions::Job).lookup("outputs") }
|
||||
|
||||
/**
|
||||
* Reusable workflow jobs may have Uses children
|
||||
@@ -158,27 +160,9 @@ class JobStmt extends Statement instanceof Actions::Job {
|
||||
* arg1: value1
|
||||
*/
|
||||
JobUsesExpr getUsesExpr() { result.getJobStmt() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* Declaration of the outputs for the job.
|
||||
* eg:
|
||||
* out1: ${steps.foo.bar}
|
||||
* out2: ${steps.foo.baz}
|
||||
*/
|
||||
class JobOutputStmt extends Statement instanceof YamlMapping {
|
||||
JobStmt job;
|
||||
|
||||
JobOutputStmt() { job.(YamlMapping).lookup("outputs") = this }
|
||||
|
||||
YamlMapping asYamlMapping() { result = this }
|
||||
|
||||
/**
|
||||
* Gets a specific value expression
|
||||
* eg: ${steps.foo.bar}
|
||||
*/
|
||||
Expression getOutputExpr(string id) {
|
||||
this.(YamlMapping).maps(any(YamlScalar s | s.getValue() = id), result)
|
||||
predicate usesReusableWorkflow() {
|
||||
this.(YamlMapping).maps(any(YamlString s | s.getValue() = "uses"), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,26 +337,60 @@ class ExprAccessExpr extends Expression instanceof YamlString {
|
||||
string getExpression() { result = expr }
|
||||
|
||||
JobStmt getJobStmt() { result.getAChildNode*() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A context access expression.
|
||||
* https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
|
||||
*/
|
||||
class CtxAccessExpr extends ExprAccessExpr {
|
||||
CtxAccessExpr() {
|
||||
expr.regexpMatch([
|
||||
stepsCtxRegex(), needsCtxRegex(), jobsCtxRegex(), envCtxRegex(), inputsCtxRegex()
|
||||
])
|
||||
}
|
||||
|
||||
abstract string getFieldName();
|
||||
|
||||
abstract Expression getRefExpr();
|
||||
}
|
||||
|
||||
private string stepsCtxRegex() {
|
||||
result = "\\bsteps\\.([A-Za-z0-9_-]+)\\.outputs\\.([A-Za-z0-9_-]+)\\b"
|
||||
}
|
||||
|
||||
private string needsCtxRegex() {
|
||||
result = "\\bneeds\\.([A-Za-z0-9_-]+)\\.outputs\\.([A-Za-z0-9_-]+)\\b"
|
||||
}
|
||||
|
||||
private string jobsCtxRegex() {
|
||||
result = "\\bjobs\\.([A-Za-z0-9_-]+)\\.outputs\\.([A-Za-z0-9_-]+)\\b"
|
||||
}
|
||||
|
||||
private string envCtxRegex() { result = "\\benv\\.([A-Za-z0-9_-]+)\\b" }
|
||||
|
||||
private string inputsCtxRegex() {
|
||||
result = "\\binputs\\.([A-Za-z0-9_-]+)\\b" or
|
||||
result = "\\bgithub\\.event\\.inputs\\.([A-Za-z0-9_-]+)\\b"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for an ExprAccessExpr accesing the `steps` context.
|
||||
* Holds for an expression accesing the `steps` context.
|
||||
* https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
|
||||
* e.g. `${{ steps.changed-files.outputs.all_changed_files }}`
|
||||
*/
|
||||
class StepOutputAccessExpr extends ExprAccessExpr {
|
||||
class StepsCtxAccessExpr extends CtxAccessExpr {
|
||||
string stepId;
|
||||
string varName;
|
||||
string fieldName;
|
||||
|
||||
StepOutputAccessExpr() {
|
||||
stepId =
|
||||
this.getExpression().regexpCapture("steps\\.([A-Za-z0-9_-]+)\\.outputs\\.[A-Za-z0-9_-]+", 1) and
|
||||
varName =
|
||||
this.getExpression().regexpCapture("steps\\.[A-Za-z0-9_-]+\\.outputs\\.([A-Za-z0-9_-]+)", 1)
|
||||
StepsCtxAccessExpr() {
|
||||
expr.regexpMatch(stepsCtxRegex()) and
|
||||
stepId = expr.regexpCapture(stepsCtxRegex(), 1) and
|
||||
fieldName = expr.regexpCapture(stepsCtxRegex(), 2)
|
||||
}
|
||||
|
||||
override string getFieldName() { result = fieldName }
|
||||
|
||||
override Expression getRefExpr() {
|
||||
this.getLocation().getFile() = result.getLocation().getFile() and
|
||||
result.(StepStmt).getId() = stepId
|
||||
@@ -380,79 +398,112 @@ class StepOutputAccessExpr extends ExprAccessExpr {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for an ExprAccessExpr accesing the `needs` or `job` contexts.
|
||||
* Holds for an expression accesing the `needs` context.
|
||||
* https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
|
||||
* e.g. `${{ needs.job1.outputs.foo}}` or `${{ jobs.job1.outputs.foo}}` (for reusable workflows)
|
||||
* e.g. `${{ needs.job1.outputs.foo}}`
|
||||
*/
|
||||
class JobOutputAccessExpr extends ExprAccessExpr {
|
||||
class NeedsCtxAccessExpr extends CtxAccessExpr {
|
||||
JobStmt job;
|
||||
string jobId;
|
||||
string varName;
|
||||
string fieldName;
|
||||
|
||||
JobOutputAccessExpr() {
|
||||
jobId =
|
||||
this.getExpression()
|
||||
.regexpCapture("(needs|jobs)\\.([A-Za-z0-9_-]+)\\.outputs\\.[A-Za-z0-9_-]+", 2) and
|
||||
varName =
|
||||
this.getExpression()
|
||||
.regexpCapture("(needs|jobs)\\.[A-Za-z0-9_-]+\\.outputs\\.([A-Za-z0-9_-]+)", 2)
|
||||
NeedsCtxAccessExpr() {
|
||||
expr.regexpMatch(needsCtxRegex()) and
|
||||
jobId = expr.regexpCapture(needsCtxRegex(), 1) and
|
||||
fieldName = expr.regexpCapture(needsCtxRegex(), 2) and
|
||||
job.getId() = jobId
|
||||
}
|
||||
|
||||
predicate usesReusableWorkflow() { job.usesReusableWorkflow() }
|
||||
|
||||
override string getFieldName() { result = fieldName }
|
||||
|
||||
override Expression getRefExpr() {
|
||||
job.getLocation().getFile() = this.getLocation().getFile() and
|
||||
(
|
||||
// regular jobs
|
||||
job.getOutputsStmt() = result
|
||||
or
|
||||
// reusable workflow calling jobs
|
||||
job.getUsesExpr() = result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for an expression accesing the `jobs` context.
|
||||
* https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
|
||||
* e.g. `${{ jobs.job1.outputs.foo}}` (within reusable workflows)
|
||||
*/
|
||||
class JobsCtxAccessExpr extends CtxAccessExpr {
|
||||
string jobId;
|
||||
string fieldName;
|
||||
|
||||
JobsCtxAccessExpr() {
|
||||
expr.regexpMatch(jobsCtxRegex()) and
|
||||
jobId = expr.regexpCapture(jobsCtxRegex(), 1) and
|
||||
fieldName = expr.regexpCapture(jobsCtxRegex(), 2)
|
||||
}
|
||||
|
||||
override string getFieldName() { result = fieldName }
|
||||
|
||||
override Expression getRefExpr() {
|
||||
exists(JobStmt job |
|
||||
job.getId() = jobId and
|
||||
job.getLocation().getFile() = this.getLocation().getFile() and
|
||||
(
|
||||
// A Job can have multiple outputs, so we need to check both
|
||||
// jobs.<job_id>.outputs.<output_name>
|
||||
job.getOutputStmt().getOutputExpr(varName) = result
|
||||
or
|
||||
// jobs.<job_id>.uses (variables returned from the reusable workflow
|
||||
job.getUsesExpr() = result
|
||||
)
|
||||
job.getOutputsStmt() = result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for an ExprAccessExpr accesing the `inputs` context.
|
||||
* Holds for an expression the `inputs` context.
|
||||
* https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
|
||||
* e.g. `${{ inputs.foo }}`
|
||||
*/
|
||||
class InputAccessExpr extends ExprAccessExpr {
|
||||
string paramName;
|
||||
class InputsCtxAccessExpr extends CtxAccessExpr {
|
||||
string fieldName;
|
||||
|
||||
InputAccessExpr() {
|
||||
paramName = this.getExpression().regexpCapture("inputs\\.([A-Za-z0-9_-]+)", 1)
|
||||
InputsCtxAccessExpr() {
|
||||
expr.regexpMatch(inputsCtxRegex()) and
|
||||
fieldName = expr.regexpCapture(inputsCtxRegex(), 1)
|
||||
}
|
||||
|
||||
override string getFieldName() { result = fieldName }
|
||||
|
||||
override Expression getRefExpr() {
|
||||
exists(ReusableWorkflowStmt w |
|
||||
w.getLocation().getFile() = this.getLocation().getFile() and
|
||||
w.getInputsStmt().getInputExpr(paramName) = result
|
||||
w.getInputsStmt().getInputExpr(fieldName) = result
|
||||
)
|
||||
or
|
||||
exists(CompositeActionStmt a |
|
||||
a.getLocation().getFile() = this.getLocation().getFile() and
|
||||
a.getInputsStmt().getInputExpr(paramName) = result
|
||||
a.getInputsStmt().getInputExpr(fieldName) = result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for an ExprAccessExpr accesing the `env` context.
|
||||
* Holds for an expression accesing the `env` context.
|
||||
* https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
|
||||
* e.g. `${{ env.foo }}`
|
||||
*/
|
||||
class EnvAccessExpr extends ExprAccessExpr {
|
||||
string varName;
|
||||
class EnvCtxAccessExpr extends CtxAccessExpr {
|
||||
string fieldName;
|
||||
|
||||
EnvAccessExpr() { varName = this.getExpression().regexpCapture("env\\.([A-Za-z0-9_-]+)", 1) }
|
||||
EnvCtxAccessExpr() {
|
||||
expr.regexpMatch(envCtxRegex()) and
|
||||
fieldName = expr.regexpCapture(envCtxRegex(), 1)
|
||||
}
|
||||
|
||||
override string getFieldName() { result = fieldName }
|
||||
|
||||
override Expression getRefExpr() {
|
||||
exists(JobUsesExpr s | s.getEnvExpr(varName) = result)
|
||||
exists(JobUsesExpr s | s.getEnvExpr(fieldName) = result)
|
||||
or
|
||||
exists(StepUsesExpr s | s.getEnvExpr(varName) = result)
|
||||
exists(StepUsesExpr s | s.getEnvExpr(fieldName) = result)
|
||||
or
|
||||
exists(RunExpr s | s.getEnvExpr(varName) = result)
|
||||
exists(RunExpr s | s.getEnvExpr(fieldName) = result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ module DataFlow {
|
||||
private import codeql.actions.dataflow.internal.DataFlowImplSpecific
|
||||
import DataFlowMake<ActionsDataFlow>
|
||||
import codeql.actions.dataflow.internal.DataFlowPublic
|
||||
|
||||
/** debug */
|
||||
// debug
|
||||
private import codeql.actions.dataflow.internal.TaintTrackingImplSpecific
|
||||
import codeql.dataflow.internal.DataFlowImplConsistency as DFIC
|
||||
|
||||
module ActionsConsistency implements DFIC::InputSig<ActionsDataFlow> { }
|
||||
|
||||
module Consistency {
|
||||
import DFIC::MakeConsistency<ActionsDataFlow, ActionsTaintTracking, ActionsConsistency>
|
||||
}
|
||||
import DFIC::MakeConsistency<ActionsDataFlow, ActionsTaintTracking, ActionsConsistency>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,8 +294,10 @@ module Actions {
|
||||
/** Gets the owner and name of the repository where the Action comes from, e.g. `actions/checkout` in `actions/checkout@v2`. */
|
||||
string getGitHubRepository() {
|
||||
result =
|
||||
this.getValue().regexpCapture(usesParser(), 1) + "/" +
|
||||
this.getValue().regexpCapture(usesParser(), 2)
|
||||
(
|
||||
this.getValue().regexpCapture(usesParser(), 1) + "/" +
|
||||
this.getValue().regexpCapture(usesParser(), 2)
|
||||
).toLowerCase()
|
||||
}
|
||||
|
||||
/** Gets the version reference used when checking out the Action, e.g. `v2` in `actions/checkout@v2`. */
|
||||
|
||||
@@ -231,7 +231,7 @@ private class JobTree extends StandardPreOrderTree instanceof JobStmt {
|
||||
rank[i](Expression child, Location l |
|
||||
(
|
||||
child = super.getAStepStmt() or
|
||||
child = super.getOutputStmt() or
|
||||
child = super.getOutputsStmt() or
|
||||
child = super.getUsesExpr()
|
||||
) and
|
||||
l = child.getLocation()
|
||||
@@ -243,25 +243,9 @@ private class JobTree extends StandardPreOrderTree instanceof JobStmt {
|
||||
}
|
||||
}
|
||||
|
||||
private class JobOutputTree extends StandardPreOrderTree instanceof JobOutputStmt {
|
||||
override ControlFlowTree getChildNode(int i) { result = super.asYamlMapping().getValueNode(i) }
|
||||
}
|
||||
private class UsesExprTree extends LeafTree instanceof UsesExpr { }
|
||||
|
||||
private class StepUsesTree extends StandardPreOrderTree instanceof StepUsesExpr {
|
||||
override ControlFlowTree getChildNode(int i) {
|
||||
result =
|
||||
rank[i](Expression child, Location l |
|
||||
(child = super.getArgumentExpr(_) or child = super.getEnvExpr(_)) and
|
||||
l = child.getLocation()
|
||||
|
|
||||
child
|
||||
order by
|
||||
l.getStartLine(), l.getStartColumn(), l.getEndColumn(), l.getEndLine(), child.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class JobUsesTree extends StandardPreOrderTree instanceof JobUsesExpr {
|
||||
private class UsesTree extends StandardPreOrderTree instanceof UsesExpr {
|
||||
override ControlFlowTree getChildNode(int i) {
|
||||
result =
|
||||
rank[i](Expression child, Location l |
|
||||
|
||||
@@ -2,21 +2,31 @@ private import internal.ExternalFlowExtensions as Extensions
|
||||
import codeql.actions.DataFlow
|
||||
import actions
|
||||
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
/**
|
||||
* MaD sources
|
||||
* Fields:
|
||||
* - action: Fully-qualified action name (NWO)
|
||||
* - version: Either '*' or a specific SHA/Tag
|
||||
* - output arg: To node (prefixed with either `env.` or `output.`)
|
||||
* - trigger: Triggering event under which this model introduces tainted data. Use `*` for any event.
|
||||
*/
|
||||
predicate sourceModel(string action, string version, string output, string trigger, string kind) {
|
||||
Extensions::sourceModel(action, version, output, trigger, kind)
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
/**
|
||||
* MaD summaries
|
||||
* Fields:
|
||||
* - action: Fully-qualified action name (NWO)
|
||||
* - version: Either '*' or a specific SHA/Tag
|
||||
* - input arg: From node (prefixed with either `env.` or `input.`)
|
||||
* - output arg: To node (prefixed with either `env.` or `output.`)
|
||||
* - kind: Either 'Taint' or 'Value'
|
||||
*/
|
||||
predicate summaryModel(string action, string version, string input, string output, string kind) {
|
||||
Extensions::summaryModel(action, version, input, output, kind)
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate sinkModel(string action, string version, string input, string kind) {
|
||||
Extensions::sinkModel(action, version, input, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* MaD sinks
|
||||
* Fields:
|
||||
@@ -25,15 +35,67 @@ predicate sinkModel(string action, string version, string input, string kind) {
|
||||
* - input: sink node (prefixed with either `env.` or `input.`)
|
||||
* - kind: sink kind
|
||||
*/
|
||||
predicate sinkNode(DataFlow::ExprNode sink, string kind) {
|
||||
predicate sinkModel(string action, string version, string input, string kind) {
|
||||
Extensions::sinkModel(action, version, input, kind)
|
||||
}
|
||||
|
||||
predicate externallyDefinedSource(DataFlow::Node source, string sourceType, string fieldName) {
|
||||
exists(UsesExpr uses, string action, string version, string trigger, string kind |
|
||||
sourceModel(action, version, fieldName, trigger, kind) and
|
||||
uses.getCallee() = action.toLowerCase() and
|
||||
(
|
||||
if version.trim() = "*"
|
||||
then uses.getVersion() = any(string v)
|
||||
else uses.getVersion() = version.trim()
|
||||
) and
|
||||
(
|
||||
if fieldName.trim().matches("env.%")
|
||||
then source.asExpr() = uses.getEnvExpr(fieldName.trim().replaceAll("env.", ""))
|
||||
else
|
||||
if fieldName.trim().matches("output.%")
|
||||
then source.asExpr() = uses
|
||||
else none()
|
||||
) and
|
||||
sourceType = kind
|
||||
)
|
||||
}
|
||||
|
||||
predicate externallyDefinedStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::ContentSet c
|
||||
) {
|
||||
exists(UsesExpr uses, string action, string version, string input, string output |
|
||||
summaryModel(action, version, input, output, "taint") and
|
||||
c = any(DataFlow::FieldContent ct | ct.getName() = output.replaceAll("output.", "")) and
|
||||
uses.getCallee() = action.toLowerCase() and
|
||||
(
|
||||
if version.trim() = "*"
|
||||
then uses.getVersion() = any(string v)
|
||||
else uses.getVersion() = version.trim()
|
||||
) and
|
||||
(
|
||||
if input.trim().matches("env.%")
|
||||
then pred.asExpr() = uses.getEnvExpr(input.trim().replaceAll("env.", ""))
|
||||
else
|
||||
if input.trim().matches("input.%")
|
||||
then pred.asExpr() = uses.getArgumentExpr(input.trim().replaceAll("input.", ""))
|
||||
else none()
|
||||
) and
|
||||
succ.asExpr() = uses
|
||||
)
|
||||
}
|
||||
|
||||
predicate externallyDefinedSink(DataFlow::ExprNode sink, string kind) {
|
||||
exists(UsesExpr uses, string action, string version, string input |
|
||||
(
|
||||
if input.trim().matches("env.%")
|
||||
then sink.asExpr() = uses.getEnvExpr(input.trim().replaceAll("input\\.", ""))
|
||||
else sink.asExpr() = uses.getArgumentExpr(input.trim())
|
||||
then sink.asExpr() = uses.getEnvExpr(input.trim().replaceAll("env.", ""))
|
||||
else
|
||||
if input.trim().matches("input.%")
|
||||
then sink.asExpr() = uses.getArgumentExpr(input.trim().replaceAll("input.", ""))
|
||||
else none()
|
||||
) and
|
||||
sinkModel(action, version, input, kind) and
|
||||
uses.getCallee() = action and
|
||||
uses.getCallee() = action.toLowerCase() and
|
||||
(
|
||||
if version.trim() = "*"
|
||||
then uses.getVersion() = any(string v)
|
||||
|
||||
@@ -126,44 +126,18 @@ private class EventSource extends RemoteFlowSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* MaD sources
|
||||
* Fields:
|
||||
* - action: Fully-qualified action name (NWO)
|
||||
* - version: Either '*' or a specific SHA/Tag
|
||||
* - output arg: To node (prefixed with either `env.` or `output.`)
|
||||
* - trigger: Triggering event under which this model introduces tainted data. Use `*` for any event.
|
||||
* A Source of untrusted data defined in a MaD specification
|
||||
*/
|
||||
private class ExternallyDefinedSource extends RemoteFlowSource {
|
||||
string soutceType;
|
||||
string sourceType;
|
||||
|
||||
ExternallyDefinedSource() {
|
||||
exists(
|
||||
UsesExpr uses, string action, string version, string output, string trigger, string kind
|
||||
|
|
||||
sourceModel(action, version, output, trigger, kind) and
|
||||
uses.getCallee() = action and
|
||||
(
|
||||
if version.trim() = "*"
|
||||
then uses.getVersion() = any(string v)
|
||||
else uses.getVersion() = version.trim()
|
||||
) and
|
||||
(
|
||||
if output.trim().matches("env.%")
|
||||
then this.asExpr() = uses.getEnvExpr(output.trim().replaceAll("output\\.", ""))
|
||||
else
|
||||
// 'output.' is the default qualifier
|
||||
// TODO: Taint just the specified output
|
||||
this.asExpr() = uses
|
||||
) and
|
||||
soutceType = kind
|
||||
)
|
||||
}
|
||||
ExternallyDefinedSource() { externallyDefinedSource(this, sourceType, _) }
|
||||
|
||||
override string getSourceType() { result = soutceType }
|
||||
override string getSourceType() { result = sourceType }
|
||||
}
|
||||
|
||||
/**
|
||||
* Composite action input sources
|
||||
* An input for a Composite Action
|
||||
*/
|
||||
private class CompositeActionInputSource extends RemoteFlowSource {
|
||||
CompositeActionStmt c;
|
||||
|
||||
@@ -21,42 +21,6 @@ class AdditionalTaintStep extends Unit {
|
||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||
}
|
||||
|
||||
/**
|
||||
* MaD summaries
|
||||
* Fields:
|
||||
* - action: Fully-qualified action name (NWO)
|
||||
* - version: Either '*' or a specific SHA/Tag
|
||||
* - input arg: From node (prefixed with either `env.` or `input.`)
|
||||
* - output arg: To node (prefixed with either `env.` or `output.`)
|
||||
* - kind: Either 'Taint' or 'Value'
|
||||
*/
|
||||
predicate externallyDefinedSummary(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(UsesExpr uses, string action, string version, string input |
|
||||
// `output` not used yet
|
||||
summaryModel(action, version, input, _, "taint") and
|
||||
uses.getCallee() = action and
|
||||
(
|
||||
if version.trim() = "*"
|
||||
then uses.getVersion() = any(string v)
|
||||
else uses.getVersion() = version.trim()
|
||||
) and
|
||||
(
|
||||
if input.trim().matches("env.%")
|
||||
then pred.asExpr() = uses.getEnvExpr(input.trim().replaceAll("env\\.", ""))
|
||||
else
|
||||
// 'input.' is the default qualifier
|
||||
pred.asExpr() = uses.getArgumentExpr(input.trim().replaceAll("input\\.", ""))
|
||||
) and
|
||||
succ.asExpr() = uses
|
||||
)
|
||||
}
|
||||
|
||||
private class ExternallyDefinedSummary extends AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
externallyDefinedSummary(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a Run step declares an environment variable, uses it in its script and sets an output in its script.
|
||||
* e.g.
|
||||
@@ -65,27 +29,22 @@ private class ExternallyDefinedSummary extends AdditionalTaintStep {
|
||||
* env:
|
||||
* BODY: ${{ github.event.comment.body }}
|
||||
* run: |
|
||||
* INITIAL_URL=$(echo "$BODY" | grep -o 'https://github.com/github/release-assets/assets/[^ >]*')
|
||||
* echo "Cleaned Initial URL: $INITIAL_URL"
|
||||
* echo "::set-output name=initial_url::$INITIAL_URL"
|
||||
* echo "::set-output name=foo::$BODY"
|
||||
* echo "foo=$(echo $BODY)" >> $GITHUB_OUTPUT
|
||||
* echo "foo=$(echo $BODY)" >> "$GITHUB_OUTPUT"
|
||||
*/
|
||||
private class RunEnvToScriptStep extends AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
runEnvToScriptstep(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
predicate runEnvToScriptstep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(RunExpr r, string varName |
|
||||
predicate runEnvToScriptStoreStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::ContentSet c) {
|
||||
exists(RunExpr r, string varName, string output |
|
||||
c = any(DataFlow::FieldContent ct | ct.getName() = output.replaceAll("output\\.", "")) and
|
||||
r.getEnvExpr(varName) = pred.asExpr() and
|
||||
exists(string script, string line |
|
||||
script = r.getScript() and
|
||||
line = script.splitAt("\n") and
|
||||
(
|
||||
line.regexpMatch(".*::set-output\\s+name.*") or
|
||||
line.regexpMatch(".*>>\\s*\\$GITHUB_OUTPUT.*")
|
||||
output = line.regexpCapture(".*::set-output\\s+name=(.*)::.*", 1) or
|
||||
output = line.regexpCapture(".*echo\\s*\"(.*)=.*\\s*>>\\s*(\")?\\$GITHUB_OUTPUT.*", 1)
|
||||
) and
|
||||
script.indexOf("$" + ["", "{", "ENV{"] + varName) > 0
|
||||
line.indexOf("$" + ["", "{", "ENV{"] + varName) > 0
|
||||
) and
|
||||
succ.asExpr() = r
|
||||
)
|
||||
|
||||
@@ -4,6 +4,8 @@ private import codeql.actions.Cfg as Cfg
|
||||
private import codeql.Locations
|
||||
private import codeql.actions.controlflow.BasicBlocks
|
||||
private import DataFlowPublic
|
||||
private import codeql.actions.dataflow.ExternalFlow
|
||||
private import codeql.actions.dataflow.FlowSteps
|
||||
|
||||
cached
|
||||
newtype TNode = TExprNode(DataFlowExpr e)
|
||||
@@ -56,7 +58,7 @@ class DataFlowExpr extends Cfg::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call corresponds to a Uses steps where a 3rd party action or a reusable workflow gets called
|
||||
* A call corresponds to a Uses steps where a 3rd party action or a reusable workflow get called
|
||||
*/
|
||||
class DataFlowCall instanceof Cfg::Node {
|
||||
DataFlowCall() { super.getAstNode() instanceof UsesExpr }
|
||||
@@ -129,25 +131,19 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { t1 = t2 }
|
||||
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
|
||||
private newtype TContent = TNoContent() { none() }
|
||||
newtype TContent =
|
||||
TFieldContent(string name) {
|
||||
// We only use field flow for steps and jobs outputs, not for accessing other context fields such as env or inputs
|
||||
name = any(StepsCtxAccessExpr a).getFieldName() or
|
||||
name = any(NeedsCtxAccessExpr a).getFieldName() or
|
||||
name = any(JobsCtxAccessExpr a).getFieldName()
|
||||
}
|
||||
|
||||
class Content extends TContent {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
}
|
||||
predicate forceHighPrecision(Content c) { c instanceof FieldContent }
|
||||
|
||||
predicate forceHighPrecision(Content c) { none() }
|
||||
class ContentApprox = ContentSet;
|
||||
|
||||
newtype TContentSet = TNoContentSet() { none() }
|
||||
|
||||
private newtype TContentApprox = TNoContentApprox() { none() }
|
||||
|
||||
class ContentApprox extends TContentApprox {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
ContentApprox getContentApprox(Content c) { none() }
|
||||
ContentApprox getContentApprox(Content c) { result = c }
|
||||
|
||||
/**
|
||||
* Made a string to match the ArgumentPosition type.
|
||||
@@ -168,12 +164,16 @@ class ArgumentPosition extends string {
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if there is a local flow step between a ${{}} expression accesing a step output variable and the step output itself
|
||||
* e.g. ${{ steps.step1.output.foo }}
|
||||
* Holds if there is a local flow step between a ${{ steps.xxx.outputs.yyy }} expression accesing a step output field
|
||||
* and the step output itself. But only for those cases where the step output is defined externally in a MaD Source
|
||||
* specification. The reason for this is that we don't currently have a way to specify that a source starts with a
|
||||
* non-empty access path so we cannot write a Source that stores the taint in a Content, we can only do that for steps
|
||||
* (storeStep). The easiest thing is to add this local flow step that simulates a read step from the source node for a specific
|
||||
* field name.
|
||||
*/
|
||||
predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(StepStmt astFrom, StepOutputAccessExpr astTo |
|
||||
(astFrom instanceof UsesExpr or astFrom instanceof RunExpr) and
|
||||
exists(UsesExpr astFrom, StepsCtxAccessExpr astTo |
|
||||
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName()) and
|
||||
astFrom = nodeFrom.asExpr() and
|
||||
astTo = nodeTo.asExpr() and
|
||||
astTo.getRefExpr() = astFrom
|
||||
@@ -181,11 +181,16 @@ predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local flow step between a ${{}} expression accesing a job output variable and the job output itself
|
||||
* e.g. ${{ needs.job1.output.foo }} or ${{ job.job1.output.foo }}
|
||||
* Holds if there is a local flow step between a ${{ needs.xxx.outputs.yyy }} expression accesing a job output field
|
||||
* and the step output itself. But only for those cases where the job (needs) output is defined externally in a MaD Source
|
||||
* specification. The reason for this is that we don't currently have a way to specify that a source starts with a
|
||||
* non-empty access path so we cannot write a Source that stores the taint in a Content, we can only do that for steps
|
||||
* (storeStep). The easiest thing is to add this local flow step that simulates a read step from the source node for a specific
|
||||
* field name.
|
||||
*/
|
||||
predicate jobsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(Expression astFrom, JobOutputAccessExpr astTo |
|
||||
predicate needsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(UsesExpr astFrom, NeedsCtxAccessExpr astTo |
|
||||
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName()) and
|
||||
astFrom = nodeFrom.asExpr() and
|
||||
astTo = nodeTo.asExpr() and
|
||||
astTo.getRefExpr() = astFrom
|
||||
@@ -197,7 +202,7 @@ predicate jobsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
* e.g. ${{ inputs.foo }}
|
||||
*/
|
||||
predicate inputsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(Expression astFrom, InputAccessExpr astTo |
|
||||
exists(Expression astFrom, InputsCtxAccessExpr astTo |
|
||||
astFrom = nodeFrom.asExpr() and
|
||||
astTo = nodeTo.asExpr() and
|
||||
astTo.getRefExpr() = astFrom
|
||||
@@ -209,10 +214,13 @@ predicate inputsCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
* e.g. ${{ env.foo }}
|
||||
*/
|
||||
predicate envCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(Expression astFrom, EnvAccessExpr astTo |
|
||||
exists(Expression astFrom, EnvCtxAccessExpr astTo |
|
||||
astFrom = nodeFrom.asExpr() and
|
||||
astTo = nodeTo.asExpr() and
|
||||
astTo.getRefExpr() = astFrom
|
||||
(
|
||||
externallyDefinedSource(nodeFrom, _, "env." + astTo.getFieldName()) or
|
||||
astTo.getRefExpr() = astFrom
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -224,7 +232,7 @@ predicate envCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
pragma[nomagic]
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
stepsCtxLocalStep(nodeFrom, nodeTo) or
|
||||
jobsCtxLocalStep(nodeFrom, nodeTo) or
|
||||
needsCtxLocalStep(nodeFrom, nodeTo) or
|
||||
inputsCtxLocalStep(nodeFrom, nodeTo) or
|
||||
envCtxLocalStep(nodeFrom, nodeTo)
|
||||
}
|
||||
@@ -244,19 +252,53 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { localFlowStep(nodeFr
|
||||
*/
|
||||
predicate jumpStep(Node nodeFrom, Node nodeTo) { none() }
|
||||
|
||||
/**
|
||||
* Holds if a CtxAccessExpr reads a field from a job (needs/jobs), step (steps) output via a read of `c` (fieldname)
|
||||
*/
|
||||
predicate ctxFieldReadStep(Node node1, Node node2, ContentSet c) {
|
||||
exists(CtxAccessExpr access |
|
||||
(
|
||||
access instanceof NeedsCtxAccessExpr or
|
||||
access instanceof StepsCtxAccessExpr or
|
||||
access instanceof JobsCtxAccessExpr
|
||||
) and
|
||||
c = any(FieldContent ct | ct.getName() = access.getFieldName()) and
|
||||
node1.asExpr() = access.getRefExpr() and
|
||||
node2.asExpr() = access
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
|
||||
* `node1` references an object with a content `c.getAReadContent()` whose
|
||||
* value ends up in `node2`.
|
||||
* Store steps without corresponding reads are pruned aggressively very early, since they can never contribute to a complete path.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) { none() }
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) { ctxFieldReadStep(node1, node2, c) }
|
||||
|
||||
/**
|
||||
* Stores an output expression (node1) into its OutputsStm node (node2)
|
||||
* using the output variable name as the access path
|
||||
*/
|
||||
predicate fieldStoreStep(Node node1, Node node2, ContentSet c) {
|
||||
exists(OutputsStmt out, string fieldName |
|
||||
node1.asExpr() = out.getOutputExpr(fieldName) and
|
||||
node2.asExpr() = out and
|
||||
c = any(FieldContent ct | ct.getName() = fieldName)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a store into `c`. Thus,
|
||||
* `node2` references an object with a content `c.getAStoreContent()` that
|
||||
* contains the value of `node1`.
|
||||
* Store steps without corresponding reads are pruned aggressively very early, since they can never contribute to a complete path.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { none() }
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
fieldStoreStep(node1, node2, c) or
|
||||
externallyDefinedStoreStep(node1, node2, c) or
|
||||
runEnvToScriptStoreStep(node1, node2, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`. For example,
|
||||
|
||||
@@ -66,6 +66,17 @@ class ParameterNode extends ExprNode {
|
||||
InputExpr getInputExpr() { result = input }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a data flow callable (Uses).
|
||||
*/
|
||||
class CallNode extends ExprNode {
|
||||
private DataFlowCall call;
|
||||
|
||||
CallNode() { this.getCfgNode() instanceof DataFlowCall }
|
||||
|
||||
string getCallee() { result = this.getCfgNode().(DataFlowCall).getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument to a Uses step (call).
|
||||
*/
|
||||
@@ -83,18 +94,18 @@ class ArgumentNode extends ExprNode {
|
||||
* Reusable workflow output nodes
|
||||
*/
|
||||
class ReturnNode extends ExprNode {
|
||||
private OutputExpr output;
|
||||
private OutputsStmt outputs;
|
||||
|
||||
ReturnNode() {
|
||||
this.asExpr() = output and
|
||||
output = any(OutputsStmt s).getOutputExpr(_)
|
||||
this.asExpr() = outputs and
|
||||
outputs = any(ReusableWorkflowStmt s).getOutputsStmt()
|
||||
}
|
||||
|
||||
ReturnKind getKind() { result = TNormalReturn() }
|
||||
|
||||
override string toString() { result = "output " + output.toString() }
|
||||
override string toString() { result = "output " + outputs.toString() }
|
||||
|
||||
override Location getLocation() { result = output.getLocation() }
|
||||
override Location getLocation() { result = outputs.getLocation() }
|
||||
}
|
||||
|
||||
/** Gets the node corresponding to `e`. */
|
||||
@@ -106,13 +117,63 @@ Node exprNode(DataFlowExpr e) { result = TExprNode(e) }
|
||||
* The set may be interpreted differently depending on whether it is
|
||||
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||
*/
|
||||
class ContentSet extends TContentSet {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
class ContentSet instanceof Content {
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { none() }
|
||||
Content getAStoreContent() { result = this }
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
Content getAReadContent() { none() }
|
||||
Content getAReadContent() { result = this }
|
||||
|
||||
/** Gets a textual representation of this content set. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference contained in an object. Examples include instance fields, the
|
||||
* contents of a collection object, the contents of an array or pointer.
|
||||
*/
|
||||
class Content extends TContent {
|
||||
/** Gets the type of the contained data for the purpose of type pruning. */
|
||||
DataFlowType getType() { any() }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
/** A field of an object, for example an instance variable. */
|
||||
class FieldContent extends Content, TFieldContent {
|
||||
private string name;
|
||||
|
||||
FieldContent() { this = TFieldContent(name) }
|
||||
|
||||
/** Gets the name of the field. */
|
||||
string getName() { result = name }
|
||||
|
||||
override string toString() { result = name }
|
||||
}
|
||||
|
||||
7
ql/lib/ext/PLACEHOLDER.model.yml
Normal file
7
ql/lib/ext/PLACEHOLDER.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["","","",""]
|
||||
|
||||
17
ql/lib/ext/TEST-RW-MODELS.model.yml
Normal file
17
ql/lib/ext/TEST-RW-MODELS.model.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["octo-org/this-repo/.github/workflows/workflow.yml", "*", "input.config-path", "output.workflow-output", "taint"]
|
||||
- ["octo-org/summary-repo/.github/workflows/workflow.yml", "*", "input.config-path", "output.workflow-output", "taint"]
|
||||
- addsTo:
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["octo-org/source-repo/.github/workflows/workflow.yml", "*", "output.workflow-output", "*", "Foo"]
|
||||
- addsTo:
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["octo-org/sink-repo/.github/workflows/workflow.yml", "*", "input.config-path", "expression-injection"]
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["ahmadnassri/action-changed-files", "*", "output.files", "pull_request", "PR changed files"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["dorny/paths-filter", "*", "output.changes", "pull_request", "PR changed files"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["frabert/replace-string-action", "*", "input.string", "output.replaced", "taint"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["jitterbit/get-changed-files", "*", "output.all", "pull_request", "PR changed files"]
|
||||
@@ -16,4 +16,4 @@ extensions:
|
||||
- ["jitterbit/get-changed-files", "*", "output.added_modified", "pull_request", "PR changed files"]
|
||||
- ["jitterbit/get-changed-files", "*", "output.added_modified", "pull_request_target", "PR changed files"]
|
||||
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request", "PR changed files"]
|
||||
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request_target", "PR changed files"]
|
||||
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request_target", "PR changed files"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["mad9000/actions-find-and-replace-string", "*", "input.source", "output.value", "taint"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["tj-actions/changed-files", "*", "output.added_files", "pull_request", "PR changed files"]
|
||||
@@ -36,4 +36,4 @@ extensions:
|
||||
- ["tj-actions/changed-files", "*", "output.modified_keys", "pull_request", "PR changed files"]
|
||||
- ["tj-actions/changed-files", "*", "output.modified_keys", "pull_request_target", "PR changed files"]
|
||||
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request", "PR changed files"]
|
||||
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request_target", "PR changed files"]
|
||||
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request_target", "PR changed files"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
pack: githubsecuritylab/actions-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["tj-actions/verify-changed-files", "*", "output.changed-files", "pull_request", "PR changed files"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
name: codeql/actions-all
|
||||
version: 0.0.1-dev
|
||||
name: githubsecuritylab/actions-all
|
||||
version: 0.0.1
|
||||
dependencies:
|
||||
codeql/controlflow: ^0.1.7
|
||||
codeql/yaml: "*"
|
||||
|
||||
@@ -43,14 +43,9 @@ query predicate nonOrphanVarAccesses(ExprAccessExpr va, string var, AstNode pare
|
||||
|
||||
query predicate parentNodes(AstNode child, AstNode parent) { child.getParentNode() = parent }
|
||||
|
||||
query predicate cfgNodes(Cfg::Node n) {
|
||||
//any()
|
||||
n.getAstNode() instanceof OutputsStmt
|
||||
}
|
||||
query predicate cfgNodes(Cfg::Node n) { any() }
|
||||
|
||||
query predicate dfNodes(DataFlow::Node e) {
|
||||
e.getLocation().getFile().getBaseName() = "argus_case_study.yml"
|
||||
}
|
||||
query predicate dfNodes(DataFlow::Node e) { any() }
|
||||
|
||||
query predicate exprNodes(DataFlow::ExprNode e) { any() }
|
||||
|
||||
@@ -69,3 +64,7 @@ query predicate sources(string action, string version, string output, string tri
|
||||
query predicate summaries(string action, string version, string input, string output, string kind) {
|
||||
summaryModel(action, version, input, output, kind)
|
||||
}
|
||||
|
||||
query predicate calls(DataFlow::CallNode call, string callee) { callee = call.getCallee() }
|
||||
|
||||
query predicate needs(DataFlow::ExprNode e) { e.asExpr() instanceof NeedsCtxAccessExpr }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* @precision high
|
||||
* @id actions/composite-action-summaries
|
||||
* @tags actions
|
||||
* model-generator
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
@@ -17,12 +18,10 @@ import codeql.actions.dataflow.ExternalFlow
|
||||
|
||||
private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
exists(CompositeActionStmt c | c.getInputsStmt().getInputExpr(_) = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof DataFlow::ReturnNode and
|
||||
exists(CompositeActionStmt c | c.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
|
||||
}
|
||||
}
|
||||
@@ -32,5 +31,7 @@ module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
import MyFlow::PathGraph
|
||||
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where MyFlow::flowPath(source, sink)
|
||||
where
|
||||
MyFlow::flowPath(source, sink) and
|
||||
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
|
||||
select sink.getNode(), source, sink, "Summary"
|
||||
|
||||
42
ql/src/Security/CWE-020/CompositeActionsSinks.ql
Normal file
42
ql/src/Security/CWE-020/CompositeActionsSinks.ql
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @name Composite Action Sinks
|
||||
* @description Actions passing input variables to expression injection sinks.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @precision high
|
||||
* @id actions/composite-action-sinks
|
||||
* @tags actions
|
||||
* model-generator
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
import actions
|
||||
import codeql.actions.TaintTracking
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.dataflow.ExternalFlow
|
||||
|
||||
private class ExpressionInjectionSink extends DataFlow::Node {
|
||||
ExpressionInjectionSink() {
|
||||
exists(RunExpr e | e.getScriptExpr() = this.asExpr()) or
|
||||
externallyDefinedSink(this, "expression-injection")
|
||||
}
|
||||
}
|
||||
|
||||
private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(CompositeActionStmt c | c.getInputsStmt().getInputExpr(_) = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionInjectionSink }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
import MyFlow::PathGraph
|
||||
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where
|
||||
MyFlow::flowPath(source, sink) and
|
||||
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
|
||||
select sink.getNode(), source, sink, "Sink"
|
||||
@@ -7,6 +7,7 @@
|
||||
* @precision high
|
||||
* @id actions/composite-action-sources
|
||||
* @tags actions
|
||||
* model-generator
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
@@ -23,9 +24,15 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof DataFlow::ReturnNode and
|
||||
exists(CompositeActionStmt c | c.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
|
||||
allowImplicitRead(node, set)
|
||||
or
|
||||
isSink(node) and
|
||||
set instanceof DataFlow::FieldContent
|
||||
}
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
@@ -33,5 +40,7 @@ module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
import MyFlow::PathGraph
|
||||
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where MyFlow::flowPath(source, sink)
|
||||
where
|
||||
MyFlow::flowPath(source, sink) and
|
||||
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
|
||||
select sink.getNode(), source, sink, "Source"
|
||||
|
||||
42
ql/src/Security/CWE-020/ReusableWorkflowsSinks.ql
Normal file
42
ql/src/Security/CWE-020/ReusableWorkflowsSinks.ql
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @name Reusable Workflow Sinks
|
||||
* @description Reusable Workflows passing parameters to an expression injection sink.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @precision high
|
||||
* @id actions/reusable-wokflow-sinks
|
||||
* @tags actions
|
||||
* model-generator
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
import actions
|
||||
import codeql.actions.TaintTracking
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.dataflow.ExternalFlow
|
||||
|
||||
private class ExpressionInjectionSink extends DataFlow::Node {
|
||||
ExpressionInjectionSink() {
|
||||
exists(RunExpr e | e.getScriptExpr() = this.asExpr()) or
|
||||
externallyDefinedSink(this, "expression-injection")
|
||||
}
|
||||
}
|
||||
|
||||
private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ReusableWorkflowStmt w | w.getInputsStmt().getInputExpr(_) = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionInjectionSink }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
import MyFlow::PathGraph
|
||||
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where
|
||||
MyFlow::flowPath(source, sink) and
|
||||
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
|
||||
select sink.getNode(), source, sink, "Sink"
|
||||
46
ql/src/Security/CWE-020/ReusableWorkflowsSources.ql
Normal file
46
ql/src/Security/CWE-020/ReusableWorkflowsSources.ql
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @name Reusable Workflow Sources
|
||||
* @description Reusable Workflow that pass user-controlled data to their output variables.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @precision high
|
||||
* @id actions/reusable-workflow-sources
|
||||
* @tags actions
|
||||
* model-generator
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
import actions
|
||||
import codeql.actions.TaintTracking
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.dataflow.ExternalFlow
|
||||
|
||||
private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
not source instanceof DataFlow::ParameterNode and
|
||||
exists(ReusableWorkflowStmt w | w.getAChildNode*() = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ReusableWorkflowStmt w | w.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
|
||||
allowImplicitRead(node, set)
|
||||
or
|
||||
isSink(node) and
|
||||
set instanceof DataFlow::FieldContent
|
||||
}
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
import MyFlow::PathGraph
|
||||
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where
|
||||
MyFlow::flowPath(source, sink) and
|
||||
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
|
||||
select sink.getNode(), source, sink, "Source"
|
||||
37
ql/src/Security/CWE-020/ReusableWorkflowsSummaries.ql
Normal file
37
ql/src/Security/CWE-020/ReusableWorkflowsSummaries.ql
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @name Reusable Workflows Summaries
|
||||
* @description Reusable workflow that pass user-controlled data to their output variables.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @precision high
|
||||
* @id actions/reusable-workflow-summaries
|
||||
* @tags actions
|
||||
* model-generator
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
import actions
|
||||
import codeql.actions.TaintTracking
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.dataflow.ExternalFlow
|
||||
|
||||
private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ReusableWorkflowStmt w | w.getInputsStmt().getInputExpr(_) = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ReusableWorkflowStmt w | w.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
import MyFlow::PathGraph
|
||||
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where
|
||||
MyFlow::flowPath(source, sink) and
|
||||
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
|
||||
select sink.getNode(), source, sink, "Summary"
|
||||
@@ -20,7 +20,7 @@ import codeql.actions.dataflow.ExternalFlow
|
||||
private class ExpressionInjectionSink extends DataFlow::Node {
|
||||
ExpressionInjectionSink() {
|
||||
exists(RunExpr e | e.getScriptExpr() = this.asExpr()) or
|
||||
sinkNode(this, "expression-injection")
|
||||
externallyDefinedSink(this, "expression-injection")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,5 +37,4 @@ import MyFlow::PathGraph
|
||||
from MyFlow::PathNode source, MyFlow::PathNode sink
|
||||
where MyFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential injection from the ${{ " + sink.getNode().asExpr().(ExprAccessExpr).getExpression() +
|
||||
" }}, which may be controlled by an external user."
|
||||
"Potential expression injection, which may be controlled by an external user."
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
- description: Standard Code Scanning queries for Actions
|
||||
- queries: .
|
||||
|
||||
- include:
|
||||
kind:
|
||||
- problem
|
||||
- path-problem
|
||||
tags contain:
|
||||
- security
|
||||
- maintainability
|
||||
|
||||
- include:
|
||||
kind:
|
||||
- diagnostic
|
||||
|
||||
- exclude:
|
||||
tags contain:
|
||||
- experimental
|
||||
- testing
|
||||
|
||||
8
ql/src/codeql-suites/actions-summaries-queries.qls
Normal file
8
ql/src/codeql-suites/actions-summaries-queries.qls
Normal file
@@ -0,0 +1,8 @@
|
||||
- description: Queries to model composite actions
|
||||
- queries: .
|
||||
|
||||
- include:
|
||||
kind:
|
||||
- path-problem
|
||||
tags contain:
|
||||
- model-generator
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
library: false
|
||||
name: codeql/actions-queries
|
||||
name: githubsecuritylab/actions-queries
|
||||
version: 0.0.1
|
||||
groups:
|
||||
- actions
|
||||
@@ -9,6 +9,6 @@ suites: codeql-suites
|
||||
extractor: yaml
|
||||
defaultSuiteFile: codeql-suites/actions-code-scanning.qls
|
||||
dependencies:
|
||||
codeql/actions-all: ${workspace}
|
||||
githubsecuritylab/actions-all: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
tests: test
|
||||
|
||||
@@ -8,17 +8,20 @@ jobs:
|
||||
uses: octo-org/this-repo/.github/workflows/reusable_workflow.yml@172239021f7ba04fe7327647b213799853a9eb89
|
||||
with:
|
||||
config-path: ${{ github.event.pull_request.head.ref }}
|
||||
secrets: inherit
|
||||
call2:
|
||||
uses: ./.github/workflows/reusable_workflow.yml
|
||||
with:
|
||||
config-path: ${{ github.event.pull_request.head.ref }}
|
||||
secrets: inherit
|
||||
call3:
|
||||
uses: octo-org/another-repo/.github/workflows/workflow.yml@v1
|
||||
uses: octo-org/summary-repo/.github/workflows/workflow.yml@v1
|
||||
with:
|
||||
config-path: ${{ github.event.pull_request.head.ref }}
|
||||
call4:
|
||||
uses: octo-org/source-repo/.github/workflows/workflow.yml@v1
|
||||
call5:
|
||||
uses: octo-org/sink-repo/.github/workflows/workflow.yml@v1
|
||||
with:
|
||||
config-path: ${{ github.event.pull_request.head.ref }}
|
||||
secrets: inherit
|
||||
|
||||
job1:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -36,3 +39,8 @@ jobs:
|
||||
needs: call3
|
||||
steps:
|
||||
- run: echo ${{ needs.call3.outputs.workflow-output }}
|
||||
job4:
|
||||
runs-on: ubuntu-latest
|
||||
needs: call4
|
||||
steps:
|
||||
- run: echo ${{ needs.call4.outputs.workflow-output }}
|
||||
|
||||
47
ql/src/test/.github/workflows/ci-cleanup.yml
vendored
47
ql/src/test/.github/workflows/ci-cleanup.yml
vendored
@@ -1,47 +0,0 @@
|
||||
run-name: Cleanup ${{ github.head_ref }}
|
||||
on:
|
||||
pull_request_target:
|
||||
types: labeled
|
||||
paths:
|
||||
- "images/**"
|
||||
|
||||
jobs:
|
||||
clean_ci:
|
||||
name: Clean CI runs
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
$startDate = Get-Date -UFormat %s
|
||||
$workflows = @("macos11", "macos12", "ubuntu2004", "ubuntu2204", "windows2019", "windows2022")
|
||||
while ($true) {
|
||||
$continue = $false
|
||||
foreach ($wf in $workflows) {
|
||||
$skippedCommand = "gh run list --workflow ${wf}.yml --branch ${{ github.event.pull_request.head.ref }} --repo ${{ github.repository }} --status skipped --json databaseId"
|
||||
$skippedIds = Invoke-Expression -Command $skippedCommand | ConvertFrom-Json | ForEach-Object { $_.databaseId }
|
||||
$skippedIds | ForEach-Object {
|
||||
$deleteCommand = "gh run delete --repo ${{ github.repository }} $_"
|
||||
Invoke-Expression -Command $deleteCommand
|
||||
}
|
||||
$pendingCommand = "gh run list --workflow ${wf}.yml --branch ${{ github.event.pull_request.head.ref }} --repo ${{ github.repository }} --status requested --json databaseId --template '{{ . | len }}'"
|
||||
$pending = Invoke-Expression -Command $pendingCommand
|
||||
if ($pending -gt 0) {
|
||||
Write-Host "Pending for ${wf}.yml: $pending run(s)"
|
||||
$continue = $true
|
||||
}
|
||||
}
|
||||
if ($continue -eq $false) {
|
||||
Write-Host "All done, exiting"
|
||||
break
|
||||
}
|
||||
$curDate = Get-Date -UFormat %s
|
||||
if (($curDate - $startDate) -gt 60) {
|
||||
Write-Host "Reached timeout, exiting"
|
||||
break
|
||||
}
|
||||
Write-Host "Waiting 5 seconds..."
|
||||
Start-Sleep -Seconds 5
|
||||
@@ -14,42 +14,24 @@ jobs:
|
||||
|
||||
- name: Extract and Clean Initial URL
|
||||
id: extract-url
|
||||
env:
|
||||
BODY: ${{ github.event.comment.body }}
|
||||
run: |
|
||||
INITIAL_URL=$(echo "${{ github.event.comment.body }}" | grep -o 'https://github.com/github/release-assets/assets/[^ >]*')
|
||||
echo "Cleaned Initial URL: $INITIAL_URL"
|
||||
echo "::set-output name=initial_url::$INITIAL_URL"
|
||||
echo "::set-output name=initial_url::$BODY"
|
||||
|
||||
- name: Get Redirected URL with Debugging
|
||||
id: curl
|
||||
env:
|
||||
INITIAL_URL: ${{ steps.extract-url.outputs.initial_url }}
|
||||
run: |
|
||||
REDIRECTED_URL=$(curl -L -o /dev/null -w %{url_effective} -sS "${{ steps.extract-url.outputs.initial_url }}")
|
||||
echo "Curl Command Executed"
|
||||
echo "Redirected URL: $REDIRECTED_URL"
|
||||
echo "::set-output name=redirected_url::$REDIRECTED_URL"
|
||||
|
||||
echo "redirected_url=$(echo $INITIAL_URL)" >> $GITHUB_OUTPUT
|
||||
- name: Trim URL after PNG
|
||||
id: trim-url
|
||||
env:
|
||||
REDIRECTED_URL: ${{ steps.curl.outputs.redirected_url }}
|
||||
run: |
|
||||
TRIMMED_URL=$(echo "${{ steps.curl.outputs.redirected_url }}" | sed 's/\(.*\.png\).*/\1/')
|
||||
echo "Trimmed URL: $TRIMMED_URL"
|
||||
echo "::set-output name=trimmed_url::$TRIMMED_URL"
|
||||
|
||||
- name: Output Final Trimmed URL
|
||||
run: |
|
||||
echo "Final Trimmed Image URL: ${{ steps.trim-url.outputs.trimmed_url }}"
|
||||
echo "trimmed_url=$(echo $REDIRECTED_URL)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Update Comment with New URL
|
||||
run: |
|
||||
COMMENT_URL="${{ github.event.comment.url }}"
|
||||
NEW_COMMENT_BODY="Use this link to include this asset in your changelog: ${{ steps.trim-url.outputs.trimmed_url }}"
|
||||
ORIGINAL_COMMENT_BODY="${{ github.event.comment.body }}"
|
||||
UPDATED_COMMENT="${ORIGINAL_COMMENT_BODY} 👀 ${NEW_COMMENT_BODY}"
|
||||
|
||||
PAYLOAD=$(jq -n --arg body "$UPDATED_COMMENT" '{"body": $body}')
|
||||
curl -X PATCH \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"${COMMENT_URL}" \
|
||||
-d "$PAYLOAD"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
name: Image URL Processing
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
process-image-url:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.comment.body, 'https://github.com/github/release-assets/assets/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Extract and Clean Initial URL
|
||||
id: extract-url
|
||||
env:
|
||||
BODY: ${{ github.event.comment.body }}
|
||||
run: |
|
||||
INITIAL_URL=$(echo "$BODY" | grep -o 'https://github.com/github/release-assets/assets/[^ >]*')
|
||||
echo "Cleaned Initial URL: $INITIAL_URL"
|
||||
echo "::set-output name=initial_url::$INITIAL_URL"
|
||||
|
||||
- name: Get Redirected URL with Debugging
|
||||
id: curl
|
||||
env:
|
||||
INITIAL_URL: ${{ steps.extract-url.outputs.initial_url }}
|
||||
run: |
|
||||
REDIRECTED_URL=$(curl -L -o /dev/null -w %{url_effective} -sS "$INITIAL_URL")
|
||||
echo "Curl Command Executed"
|
||||
echo "Redirected URL: $REDIRECTED_URL"
|
||||
echo "::set-output name=redirected_url::$REDIRECTED_URL"
|
||||
|
||||
- name: Trim URL after PNG
|
||||
id: trim-url
|
||||
env:
|
||||
REDIRECTED_URL: ${{ steps.curl.outputs.redirected_url }}
|
||||
run: |
|
||||
TRIMMED_URL=$(echo "$REDIRECTED_URL" | sed 's/\(.*\.png\).*/\1/')
|
||||
echo "Trimmed URL: $TRIMMED_URL"
|
||||
echo "::set-output name=trimmed_url::$TRIMMED_URL"
|
||||
|
||||
- name: Output Final Trimmed URL
|
||||
run: |
|
||||
echo "Final Trimmed Image URL: ${{ steps.trim-url.outputs.trimmed_url }}"
|
||||
|
||||
- name: Update Comment with New URL
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COMMENT_URL: ${{ github.event.comment.url }}
|
||||
ORIGINAL_COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
run: |
|
||||
NEW_COMMENT_BODY="Use this link to include this asset in your changelog: ${{ steps.trim-url.outputs.trimmed_url }}"
|
||||
UPDATED_COMMENT="${ORIGINAL_COMMENT_BODY} 👀 ${NEW_COMMENT_BODY}"
|
||||
|
||||
PAYLOAD=$(jq -n --arg body "$UPDATED_COMMENT" '{"body": $body}')
|
||||
curl -X PATCH \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"${COMMENT_URL}" \
|
||||
-d "$PAYLOAD"
|
||||
@@ -1,27 +0,0 @@
|
||||
name: Image URL Processing
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
process-image-url:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.comment.body, 'https://github.com/github/release-assets/assets/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Extract and Clean Initial URL
|
||||
id: source
|
||||
env:
|
||||
BODY: ${{ github.event.comment.body }}
|
||||
run: |
|
||||
INITIAL_URL=$(echo "$BODY" | grep -o 'https://github.com/github/release-assets/assets/[^ >]*')
|
||||
echo "Cleaned Initial URL: $INITIAL_URL"
|
||||
echo "::set-output name=initial_url::$INITIAL_URL"
|
||||
|
||||
- name: Get Redirected URL with Debugging
|
||||
id: sink
|
||||
run: |
|
||||
echo ${{ steps.source.outputs.initial_url }}
|
||||
9
ql/src/test/.github/workflows/simple1.yml
vendored
9
ql/src/test/.github/workflows/simple1.yml
vendored
@@ -5,12 +5,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- id: source
|
||||
- id: summary
|
||||
uses: mad9000/actions-find-and-replace-string@3
|
||||
with:
|
||||
source: ${{ github.event.head_commit.message }}
|
||||
find: 'foo'
|
||||
replace: ''
|
||||
- id: sink
|
||||
- id: flow
|
||||
run: |
|
||||
echo "${{steps.source.outputs.value}}"
|
||||
echo "${{steps.summary.outputs.value}}"
|
||||
- id: no-flow
|
||||
run: |
|
||||
echo "${{steps.summary.outputs.foo}}"
|
||||
|
||||
6
ql/src/test/.github/workflows/simple2.yml
vendored
6
ql/src/test/.github/workflows/simple2.yml
vendored
@@ -33,4 +33,10 @@ jobs:
|
||||
echo "$file was changed"
|
||||
done
|
||||
|
||||
- name: List all changed files
|
||||
id: no-flow
|
||||
run: |
|
||||
for file in ${{ steps.source.outputs.all_changed_files_count }}; do
|
||||
echo "$file was changed"
|
||||
done
|
||||
|
||||
|
||||
7
ql/src/test/.github/workflows/test.yml
vendored
7
ql/src/test/.github/workflows/test.yml
vendored
@@ -22,7 +22,9 @@ jobs:
|
||||
run: |
|
||||
Write-Output "::set-output name=MSG::$ENV{BODY}"
|
||||
- id: step2
|
||||
run: echo "test=${{steps.step1.outputs.MSG}}" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
MSG: ${{steps.step1.outputs.MSG}}
|
||||
run: echo "test=$MSG" >> "$GITHUB_OUTPUT"
|
||||
|
||||
job2:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -32,5 +34,4 @@ jobs:
|
||||
needs: job1
|
||||
|
||||
steps:
|
||||
- env:
|
||||
run: echo ${{needs.job1.outputs.job_output}}
|
||||
- run: echo ${{needs.job1.outputs.job_output}}
|
||||
|
||||
Reference in New Issue
Block a user