Fix: ControlChecks protects/dominates only work with Steps. A sink can be in a sub-step node (eg: ScalarValue)

This commit is contained in:
Alvaro Muñoz
2024-09-28 23:57:32 +02:00
parent 1b3b47bb1e
commit f2c5a14883
13 changed files with 507 additions and 17 deletions

View File

@@ -13,6 +13,8 @@ class AstNode instanceof AstNodeImpl {
string toString() { result = super.toString() }
Step getEnclosingStep() { result = super.getEnclosingStep() }
Job getEnclosingJob() { result = super.getEnclosingJob() }
Workflow getEnclosingWorkflow() { result = super.getEnclosingWorkflow() }

View File

@@ -110,6 +110,18 @@ abstract class AstNodeImpl extends TAstNode {
result = this.getEnclosingCompositeAction().getACallerJob()
}
/**
* Gets the enclosing Step.
*/
StepImpl getEnclosingStep() {
if this instanceof StepImpl
then result = this
else
if this instanceof ScalarValueImpl
then result.getAChildNode*() = this.getParentNode()
else none()
}
/**
* Gets the enclosing workflow if any.
*/

View File

@@ -37,29 +37,29 @@ abstract class ControlCheck extends AstNode {
this instanceof Run
}
predicate protects(Step step, Event event, string category) {
predicate protects(AstNode node, Event event, string category) {
// The check dominates the step it should protect
this.dominates(step) and
this.dominates(node) and
// The check is effective against the event and category
this.protectsCategoryAndEvent(category, event.getName()) and
// The check can be triggered by the event
this.getEnclosingJob().getATriggerEvent() = event
}
predicate dominates(Step step) {
predicate dominates(AstNode node) {
this instanceof If and
(
step.getIf() = this or
step.getEnclosingJob().getIf() = this or
step.getEnclosingJob().getANeededJob().(LocalJob).getAStep().getIf() = this or
step.getEnclosingJob().getANeededJob().(LocalJob).getIf() = this
node.getEnclosingStep().getIf() = this or
node.getEnclosingJob().getIf() = this or
node.getEnclosingJob().getANeededJob().(LocalJob).getAStep().getIf() = this or
node.getEnclosingJob().getANeededJob().(LocalJob).getIf() = this
)
or
this instanceof Environment and
(
step.getEnclosingJob().getEnvironment() = this
node.getEnclosingJob().getEnvironment() = this
or
step.getEnclosingJob().getANeededJob().getEnvironment() = this
node.getEnclosingJob().getANeededJob().getEnvironment() = this
)
or
(
@@ -67,9 +67,9 @@ abstract class ControlCheck extends AstNode {
this instanceof UsesStep
) and
(
this.(Step).getAFollowingStep() = step
this.(Step).getAFollowingStep() = node.getEnclosingStep()
or
step.getEnclosingJob().getANeededJob().(LocalJob).getAStep() = this.(Step)
node.getEnclosingJob().getANeededJob().(LocalJob).getAStep() = this.(Step)
)
}

View File

@@ -22,19 +22,20 @@ from EnvVarInjectionFlow::PathNode source, EnvVarInjectionFlow::PathNode sink, E
where
EnvVarInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, "envvar-injection")
) and
// exclude paths to file read sinks from non-artifact sources
(
// source is text
not source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, "code-injection")
check.protects(sink.getNode().asExpr(), event, ["envvar-injection", "code-injection"])
)
or
// source is an artifact or a file from an untrusted checkout
source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, ["untrusted-checkout", "artifact-poisoning"])
check
.protects(sink.getNode().asExpr(), event,
["envvar-injection", "untrusted-checkout", "artifact-poisoning"])
) and
(
sink.getNode() instanceof EnvVarInjectionFromFileReadSink or

View File

@@ -16,11 +16,15 @@
import actions
import codeql.actions.security.CommandInjectionQuery
import CommandInjectionFlow::PathGraph
import codeql.actions.security.ControlChecks
from CommandInjectionFlow::PathNode source, CommandInjectionFlow::PathNode sink, Event event
where
CommandInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event)
inPrivilegedContext(sink.getNode().asExpr(), event) and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, ["command-injection", "code-injection"])
)
select sink.getNode(), source, sink,
"Potential command injection in $@, which may be controlled by an external user.", sink,
sink.getNode().asExpr().(Expression).getRawExpression()

View File

@@ -0,0 +1,81 @@
name: Write prerelease comment
on:
workflow_run:
workflows: ["Create Pull Request Prerelease"]
types:
- completed
jobs:
comment:
if: ${{ github.repository_owner == 'cloudflare' }}
runs-on: ubuntu-latest
name: Write comment to the PR
steps:
- name: "Put PR and workflow ID on the environment"
uses: actions/github-script@v7
with:
script: |
// Copied from .github/extract-pr-and-workflow-id.js
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (const artifact of allArtifacts.data.artifacts) {
// Extract the PR number from the artifact name
const match = /^npm-package-(.+)-(\d+)$/.exec(artifact.name);
if (match) {
const packageName = match[1].toUpperCase();
require("fs").appendFileSync(
process.env.GITHUB_ENV,
`\nWORKFLOW_RUN_PR_FOR_${packageName}=${match[2]}` +
`\nWORKFLOW_RUN_ID_FOR_${packageName}=${context.payload.workflow_run.id}`
);
}
}
- name: "Download runtime versions"
# Regular `actions/download-artifact` doesn't support downloading
# artifacts from another workflow
uses: dawidd6/action-download-artifact@v2
with:
run_id: ${{ github.event.workflow_run.id }}
name: runtime-versions.md
- name: "Put runtime versions on the environment"
id: runtime_versions
run: |
{
echo 'RUNTIME_VERSIONS<<EOF'
cat runtime-versions.md
echo EOF
} >> "$GITHUB_ENV"
- name: "Download pre-release report"
uses: dawidd6/action-download-artifact@v2
with:
run_id: ${{ github.event.workflow_run.id }}
name: prerelease-report.md
- name: "Put pre-release report on the environment"
id: prerelease_report
run: |
{
echo 'PRERELEASE_REPORT<<EOF'
cat prerelease-report.md
echo EOF
} >> "$GITHUB_ENV"
- name: "Comment on PR with Wrangler link"
uses: marocchino/sticky-pull-request-comment@v2
with:
number: ${{ env.WORKFLOW_RUN_PR_FOR_WRANGLER }}
message: |
${{ env.PRERELEASE_REPORT }}
---
${{ env.RUNTIME_VERSIONS }}

View File

@@ -0,0 +1,80 @@
name: Write prerelease comment
on:
workflow_run:
workflows: ["Create Pull Request Prerelease"]
types:
- completed
jobs:
comment:
runs-on: ubuntu-latest
name: Write comment to the PR
steps:
- name: "Put PR and workflow ID on the environment"
uses: actions/github-script@v7
with:
script: |
// Copied from .github/extract-pr-and-workflow-id.js
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (const artifact of allArtifacts.data.artifacts) {
// Extract the PR number from the artifact name
const match = /^npm-package-(.+)-(\d+)$/.exec(artifact.name);
if (match) {
const packageName = match[1].toUpperCase();
require("fs").appendFileSync(
process.env.GITHUB_ENV,
`\nWORKFLOW_RUN_PR_FOR_${packageName}=${match[2]}` +
`\nWORKFLOW_RUN_ID_FOR_${packageName}=${context.payload.workflow_run.id}`
);
}
}
- name: "Download runtime versions"
# Regular `actions/download-artifact` doesn't support downloading
# artifacts from another workflow
uses: dawidd6/action-download-artifact@v2
with:
run_id: ${{ github.event.workflow_run.id }}
name: runtime-versions.md
- name: "Put runtime versions on the environment"
id: runtime_versions
run: |
{
echo 'RUNTIME_VERSIONS<<EOF'
cat runtime-versions.md
echo EOF
} >> "$GITHUB_ENV"
- name: "Download pre-release report"
uses: dawidd6/action-download-artifact@v2
with:
run_id: ${{ github.event.workflow_run.id }}
name: prerelease-report.md
- name: "Put pre-release report on the environment"
id: prerelease_report
run: |
{
echo 'PRERELEASE_REPORT<<EOF'
cat prerelease-report.md
echo EOF
} >> "$GITHUB_ENV"
- name: "Comment on PR with Wrangler link"
uses: marocchino/sticky-pull-request-comment@v2
with:
number: ${{ env.WORKFLOW_RUN_PR_FOR_WRANGLER }}
message: |
${{ env.PRERELEASE_REPORT }}
---
${{ env.RUNTIME_VERSIONS }}

View File

@@ -20,6 +20,14 @@ edges
| .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test9.yml:19:9:27:6 | Uses Step | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | provenance | |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | .github/workflows/test11.yml:49:14:54:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | .github/workflows/test11.yml:56:9:62:6 | Uses Step | provenance | |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | .github/workflows/test11.yml:64:14:69:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test11.yml:56:9:62:6 | Uses Step | .github/workflows/test11.yml:64:14:69:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:55:9:61:6 | Uses Step | provenance | |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
nodes
| .github/workflows/test2.yml:12:9:41:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | semmle.label | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n |
@@ -61,6 +69,14 @@ nodes
| .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | semmle.label | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | semmle.label | cat foo/.github/java-config.env >> $GITHUB_ENV |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test11.yml:49:14:54:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test11.yml:56:9:62:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test11.yml:64:14:69:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test12.yml:55:9:61:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
subpaths
#select
| .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | .github/workflows/test2.yml:12:9:41:6 | Uses Step | .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n |
@@ -84,3 +100,6 @@ subpaths
| .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n |
| .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | .github/workflows/test9.yml:19:9:27:6 | Uses Step | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n |
| .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | .github/workflows/test10.yml:20:9:26:6 | Uses Step | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | cat foo/.github/java-config.env >> $GITHUB_ENV |
| .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n |

View File

@@ -20,6 +20,14 @@ edges
| .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test9.yml:19:9:27:6 | Uses Step | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | provenance | |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | .github/workflows/test11.yml:49:14:54:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | .github/workflows/test11.yml:56:9:62:6 | Uses Step | provenance | |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | .github/workflows/test11.yml:64:14:69:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test11.yml:56:9:62:6 | Uses Step | .github/workflows/test11.yml:64:14:69:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:55:9:61:6 | Uses Step | provenance | |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
| .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | provenance | |
nodes
| .github/workflows/test2.yml:12:9:41:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | semmle.label | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n |
@@ -61,5 +69,13 @@ nodes
| .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | semmle.label | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | semmle.label | cat foo/.github/java-config.env >> $GITHUB_ENV |
| .github/workflows/test11.yml:39:9:47:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test11.yml:49:14:54:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test11.yml:56:9:62:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test11.yml:64:14:69:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test12.yml:38:9:46:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test12.yml:48:14:53:29 | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'RUNTIME_VERSIONS<<EOF'\n cat runtime-versions.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
| .github/workflows/test12.yml:55:9:61:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n | semmle.label | {\n echo 'PRERELEASE_REPORT<<EOF'\n cat prerelease-report.md\n echo EOF\n} >> "$GITHUB_ENV"\n |
subpaths
#select

View File

@@ -0,0 +1,196 @@
name: "Run Dagger pipeline"
description: "Runs a given dagger pipeline"
inputs:
subcommand:
description: "Subcommand for airbyte-ci"
required: true
context:
description: "CI context (e.g., pull_request, manual)"
required: true
github_token:
description: "GitHub token"
required: false
dagger_cloud_token:
description: "Dagger Cloud token"
required: false
docker_hub_username:
description: "Dockerhub username"
required: false
docker_hub_password:
description: "Dockerhub password"
required: false
options:
description: "Options for the subcommand"
required: false
production:
description: "Whether to run in production mode"
required: false
default: "True"
report_bucket_name:
description: "Bucket name for CI reports"
required: false
default: "airbyte-ci-reports-multi"
gcp_gsm_credentials:
description: "GCP credentials for GCP Secret Manager"
required: false
default: ""
gcp_integration_tester_credentials:
description: "GCP credentials for integration tests"
required: false
default: ""
git_repo_url:
description: "Git repository URL"
default: https://github.com/airbytehq/airbyte.git
required: false
git_branch:
description: "Git branch to checkout"
required: false
git_revision:
description: "Git revision to checkout"
required: false
slack_webhook_url:
description: "Slack webhook URL"
required: false
metadata_service_gcs_credentials:
description: "GCP credentials for metadata service"
required: false
metadata_service_bucket_name:
description: "Bucket name for metadata service"
required: false
default: "prod-airbyte-cloud-connector-metadata-service"
sentry_dsn:
description: "Sentry DSN"
required: false
spec_cache_bucket_name:
description: "Bucket name for GCS spec cache"
required: false
default: "io-airbyte-cloud-spec-cache"
spec_cache_gcs_credentials:
description: "GCP credentials for GCS spec cache"
required: false
gcs_credentials:
description: "GCP credentials for GCS"
required: false
ci_job_key:
description: "CI job key"
required: false
s3_build_cache_access_key_id:
description: "Gradle S3 Build Cache AWS access key ID"
required: false
s3_build_cache_secret_key:
description: "Gradle S3 Build Cache AWS secret key"
required: false
airbyte_ci_binary_url:
description: "URL to airbyte-ci binary"
required: false
default: https://connectors.airbyte.com/airbyte-ci/releases/ubuntu/latest/airbyte-ci
python_registry_token:
description: "Python registry API token to publish python package"
required: false
is_fork:
description: "Whether the PR is from a fork"
required: false
default: "false"
max_attempts:
description: "Number of attempts at running the airbyte-ci command"
required: false
default: 1
retry_wait_seconds:
description: "Number of seconds to wait between retry attempts"
required: false
default: 60
runs:
using: "composite"
steps:
- name: Get start timestamp
id: get-start-timestamp
shell: bash
run: echo "start-timestamp=$(date +%s)" >> $GITHUB_OUTPUT
- name: Docker login
id: docker-login
uses: docker/login-action@v3
if: ${{ inputs.docker_hub_username != '' && inputs.docker_hub_password != '' }}
with:
username: ${{ inputs.docker_hub_username }}
password: ${{ inputs.docker_hub_password }}
- name: Install Airbyte CI
id: install-airbyte-ci
uses: ./.github/actions/install-airbyte-ci
with:
airbyte_ci_binary_url: ${{ inputs.airbyte_ci_binary_url }}
is_fork: ${{ inputs.is_fork }}
- name: Run airbyte-ci
id: run-airbyte-ci
uses: nick-fields/retry@v3
env:
CI: "True"
CI_GIT_USER: ${{ github.repository_owner }}
CI_PIPELINE_START_TIMESTAMP: ${{ steps.get-start-timestamp.outputs.start-timestamp }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
# Next environment variables are workflow inputs based and can be set with empty values if the inputs are not required and passed
CI_CONTEXT: "${{ inputs.context }}"
CI_GIT_BRANCH: ${{ inputs.git_branch || github.head_ref }}
CI_GIT_REPO_URL: ${{ inputs.git_repo_url }}
CI_GIT_REVISION: ${{ inputs.git_revision || github.sha }}
CI_GITHUB_ACCESS_TOKEN: ${{ inputs.github_token }}
CI_JOB_KEY: ${{ inputs.ci_job_key }}
CI_REPORT_BUCKET_NAME: ${{ inputs.report_bucket_name }}
DAGGER_CLOUD_TOKEN: "${{ inputs.dagger_cloud_token }}"
DOCKER_HUB_PASSWORD: ${{ inputs.docker_hub_password }}
DOCKER_HUB_USERNAME: ${{ inputs.docker_hub_username }}
GCP_GSM_CREDENTIALS: ${{ inputs.gcp_gsm_credentials }}
GCP_INTEGRATION_TESTER_CREDENTIALS: ${{ inputs.gcp_integration_tester_credentials }}
GCS_CREDENTIALS: ${{ inputs.gcs_credentials }}
METADATA_SERVICE_BUCKET_NAME: ${{ inputs.metadata_service_bucket_name }}
METADATA_SERVICE_GCS_CREDENTIALS: ${{ inputs.metadata_service_gcs_credentials }}
PRODUCTION: ${{ inputs.production }}
PYTHON_REGISTRY_TOKEN: ${{ inputs.python_registry_token }}
PYTHON_REGISTRY_URL: ${{ inputs.python_registry_url }}
S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ inputs.s3_build_cache_access_key_id }}
S3_BUILD_CACHE_SECRET_KEY: ${{ inputs.s3_build_cache_secret_key }}
SENTRY_DSN: ${{ inputs.sentry_dsn }}
SLACK_WEBHOOK: ${{ inputs.slack_webhook_url }}
SPEC_CACHE_BUCKET_NAME: ${{ inputs.spec_cache_bucket_name }}
SPEC_CACHE_GCS_CREDENTIALS: ${{ inputs.spec_cache_gcs_credentials }}
with:
shell: bash
max_attempts: ${{ inputs.max_attempts }}
retry_wait_seconds: ${{ inputs.retry_wait_seconds }}
# 360mn > 6 hours: it's the GitHub runner max job duration
timeout_minutes: 360
command: |
airbyte-ci --disable-update-check --disable-dagger-run --is-ci --gha-workflow-run-id=${{ github.run_id }} ${{ inputs.subcommand }} ${{ inputs.options }}
- name: Stop Engine
id: stop-engine
if: always()
shell: bash
run: |
mapfile -t containers < <(docker ps --filter name="dagger-engine-*" -q)
if [[ "${#containers[@]}" -gt 0 ]]; then
# give 5mn to the Dagger Engine to push cache data to Dagger Cloud
docker stop -t 300 "${containers[@]}";
fi
- name: Collect dagger engine logs
id: collect-dagger-engine-logs
if: always()
uses: jwalton/gh-docker-logs@v2
with:
dest: "./dagger_engine_logs"
images: "registry.dagger.io/engine"
- name: Tar logs
id: tar-logs
if: always()
shell: bash
run: tar cvzf ./dagger_engine_logs.tgz ./dagger_engine_logs
- name: Upload logs to GitHub
id: upload-dagger-engine-logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}_dagger_engine_logs.tgz
path: ./dagger_engine_logs.tgz
retention-days: 7

View File

@@ -0,0 +1,63 @@
name: Finalize connector rollout
on:
repository_dispatch:
types: [finalize-connector-rollout]
workflow_dispatch:
inputs:
connector_name:
description: "Connector name"
required: true
action:
description: "Action to perform"
required: true
options: ["promote", "rollback"]
jobs:
finalize_rollout:
name: Finalize connector rollout
runs-on: connector-publish-large
env:
ACTION: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.action || github.event.client_payload.action }}
steps:
- name: Check action value
run: |
if [[ "${ACTION}" != "promote" && "${ACTION}" != "rollback" ]]; then
echo "Invalid action: ${ACTION}"
exit 1
fi
shell: bash
- name: Checkout Airbyte
uses: actions/checkout@v4
- name: Promote {{ github.event.client_payload.connector_name }} release candidate
id: promote-release-candidate
if: ${{ env.ACTION == 'promote' }}
uses: ./.github/actions/run-airbyte-ci
with:
context: "manual"
dagger_cloud_token: ${{ secrets.DAGGER_CLOUD_TOKEN_2 }}
docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }}
docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
gcp_gsm_credentials: ${{ secrets.GCP_GSM_CREDENTIALS }}
gcs_credentials: ${{ secrets.METADATA_SERVICE_PROD_GCS_CREDENTIALS }}
github_token: ${{ secrets.GITHUB_TOKEN }}
metadata_service_gcs_credentials: ${{ secrets.METADATA_SERVICE_PROD_GCS_CREDENTIALS }}
sentry_dsn: ${{ secrets.SENTRY_AIRBYTE_CI_DSN }}
slack_webhook_url: ${{ secrets.PUBLISH_ON_MERGE_SLACK_WEBHOOK }}
subcommand: "connectors --name=${{ github.event.client_payload.connector_name }} publish --promote-release-candidate"
- name: Rollback {{ github.event.client_payload.connector_name }} release candidate
id: rollback-release-candidate
if: ${{ env.ACTION == 'rollback' }}
uses: ./.github/actions/run-airbyte-ci
with:
context: "manual"
dagger_cloud_token: ${{ secrets.DAGGER_CLOUD_TOKEN_2 }}
docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }}
docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
gcp_gsm_credentials: ${{ secrets.GCP_GSM_CREDENTIALS }}
gcs_credentials: ${{ secrets.METADATA_SERVICE_PROD_GCS_CREDENTIALS }}
github_token: ${{ secrets.GITHUB_TOKEN }}
metadata_service_gcs_credentials: ${{ secrets.METADATA_SERVICE_PROD_GCS_CREDENTIALS }}
sentry_dsn: ${{ secrets.SENTRY_AIRBYTE_CI_DSN }}
slack_webhook_url: ${{ secrets.PUBLISH_ON_MERGE_SLACK_WEBHOOK }}
spec_cache_gcs_credentials: ${{ secrets.SPEC_CACHE_SERVICE_ACCOUNT_KEY_PUBLISH }}
subcommand: "connectors --name=${{ github.event.client_payload.connector_name }} publish --rollback-release-candidate"

View File

@@ -1,6 +1,13 @@
edges
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | provenance | |
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
nodes
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | semmle.label | input subcommand |
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | semmle.label | inputs.subcommand |
| .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | semmle.label | github.event.comment.body |
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
subpaths
#select
| .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | Potential command injection in $@, which may be controlled by an external user. | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | ${{ github.event.comment.body }} |

View File

@@ -1,5 +1,14 @@
edges
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | provenance | |
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
nodes
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | semmle.label | input subcommand |
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | semmle.label | inputs.subcommand |
| .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | semmle.label | github.event.comment.body |
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
subpaths
#select
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | Potential command injection in $@, which may be controlled by an external user. | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | ${{ inputs.subcommand }} |
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | Potential command injection in $@, which may be controlled by an external user. | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | ${{ inputs.subcommand }} |