Skip to content

Define CI Pipeline and DAST Profile relationship

What?

this merge request adds the ability to deliver secrets for dast on-demand scans via the introduction of a new table (dast_profiles_pipelines).

this merge request started as !54397 (closed) but was separated out to make review easier.

Why?

as part of the work on dast on-demand scans, we want to give users the ability to specify login credentials for their on-demand scans in order to perform authenticated scans.

during security review we identified that ci_variables seemed like the correct place to store this data but that one of the risks associated was that sensitive ci_variables could end up being sent to jobs that should not have access to them (e.g. if someone were set the environment scope incorrectly).

following discussion in review on this merge request, we opted to move away from using the ci_variables and simplify the solution by introducing a new table and extending Ci::Contextable.

Related Issue(s)

Related Merge Request(s)

Database

Migrations

% rails db:migrate:up VERSION=20210317035357 && rails db:migrate:up VERSION=20210322063407 && rails db:migrate:up VERSION=20210322063450                                                                                                                                                                                                                                        
== 20210317035357 CreateDastProfilesPipelines: migrating ======================
-- create_table(:dast_profiles_pipelines, {:primary_key=>[:dast_profile_id, :ci_pipeline_id], :comment=>"{\"owner\":\"group::dynamic analysis\",\"description\":\"Join table between DAST Profiles and CI Pipelines\"}"})
   -> 0.0145s
== 20210317035357 CreateDastProfilesPipelines: migrated (0.0147s) =============

== 20210322063407 AddDastProfileIdFkToDastProfilesPipelines: migrating ========
-- transaction_open?()
   -> 0.0000s
-- foreign_keys(:dast_profiles_pipelines)
   -> 0.0027s
-- execute("ALTER TABLE dast_profiles_pipelines\nADD CONSTRAINT fk_cc206a8c13\nFOREIGN KEY (dast_profile_id)\nREFERENCES dast_profiles (id)\nON DELETE CASCADE\nNOT VALID;\n")
   -> 0.0050s
-- execute("SET statement_timeout TO 0")
   -> 0.0005s
-- execute("ALTER TABLE dast_profiles_pipelines VALIDATE CONSTRAINT fk_cc206a8c13;")
   -> 0.0016s
-- execute("RESET ALL")
   -> 0.0007s
== 20210322063407 AddDastProfileIdFkToDastProfilesPipelines: migrated (0.0160s)

== 20210322063450 AddCiPipelineIdFkToDastProfilesPipelines: migrating =========
-- transaction_open?()
   -> 0.0000s
-- foreign_keys(:dast_profiles_pipelines)
   -> 0.0033s
-- execute("ALTER TABLE dast_profiles_pipelines\nADD CONSTRAINT fk_a60cad829d\nFOREIGN KEY (ci_pipeline_id)\nREFERENCES ci_pipelines (id)\nON DELETE CASCADE\nNOT VALID;\n")
   -> 0.0031s
-- execute("SET statement_timeout TO 0")
   -> 0.0005s
-- execute("ALTER TABLE dast_profiles_pipelines VALIDATE CONSTRAINT fk_a60cad829d;")
   -> 0.0025s
-- execute("RESET ALL")
   -> 0.0007s
== 20210322063450 AddCiPipelineIdFkToDastProfilesPipelines: migrated (0.0161s)
% rails db:migrate:down VERSION=20210322063450 && rails db:migrate:down VERSION=20210322063407 && rails db:migrate:down VERSION=20210317035357
== 20210322063450 AddCiPipelineIdFkToDastProfilesPipelines: reverting =========
-- remove_foreign_key(:dast_profiles_pipelines, {:column=>:ci_pipeline_id})
   -> 0.0163s
== 20210322063450 AddCiPipelineIdFkToDastProfilesPipelines: reverted (0.0670s)

== 20210322063407 AddDastProfileIdFkToDastProfilesPipelines: reverting ========
-- remove_foreign_key(:dast_profiles_pipelines, {:column=>:dast_profile_id})
   -> 0.0046s
== 20210322063407 AddDastProfileIdFkToDastProfilesPipelines: reverted (0.0100s)

== 20210317035357 CreateDastProfilesPipelines: reverting ======================
-- drop_table(:dast_profiles_pipelines)
   -> 0.0039s
== 20210317035357 CreateDastProfilesPipelines: reverted (0.0040s) =============

Queries

Code

project = create(:project, shared_runners_enabled: false, group_runners_enabled: false)

runner = create(:ci_runner, :project, projects: [project])

dast_profile = create(:dast_profile, project: project)

pipeline = create(:ci_pipeline, project: project, source: :ondemand_dast_scan, config_source: :parameter_source)
dast_profile.ci_pipelines << pipeline

create(:dast_site_profile_secret_variable, dast_site_profile: dast_profile.dast_site_profile)
create(:ci_build, pipeline: pipeline)

query_recorder = ActiveRecord::QueryRecorder.new do
result = Ci::RegisterJobService.new(runner).execute(session: { 'url' => 'https://example.com' })

result.valid?
result.build_json
end

puts query_recorder.log

Before

SELECT "tags"."id" FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 13 AND "taggings"."taggable_type" = 'Ci::Runner' AND "taggings"."context" = 'tags' /*application:test*/
SELECT "ci_builds"."id" FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND ("ci_builds"."status" IN ('pending')) AND "ci_builds"."runner_id" IS NULL AND "ci_builds"."project_id" IN (SELECT "projects"."id" FROM "projects" INNER JOIN "ci_runner_projects" ON "projects"."id" = "ci_runner_projects"."project_id" LEFT JOIN project_features ON projects.id = project_features.project_id WHERE "ci_runner_projects"."runner_id" = 13 AND "projects"."pending_delete" = FALSE AND ("project_features"."builds_access_level" > 0 OR "project_features"."builds_access_level" IS NULL)) AND (NOT EXISTS (SELECT 1 FROM "taggings" WHERE "taggings"."taggable_type" = 'CommitStatus' AND "taggings"."context" = 'tags' AND (taggable_id = ci_builds.id) AND 1=1)) ORDER BY id ASC /*application:test*/
SELECT "ci_builds".* FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND "ci_builds"."id" = 5 LIMIT 1 /*application:test*/
SELECT "taggings".* FROM "taggings" WHERE "taggings"."taggable_id" = 5 AND "taggings"."taggable_type" = 'CommitStatus' /*application:test*/
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 5 AND "taggings"."taggable_type" = 'CommitStatus' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) /*application:test*/
SELECT "ci_builds_runner_session".* FROM "ci_builds_runner_session" WHERE "ci_builds_runner_session"."build_id" = 5 LIMIT 1 /*application:test*/
SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_builds_metadata".* FROM "ci_builds_metadata" WHERE "ci_builds_metadata"."build_id" = 5 LIMIT 1 /*application:test*/
SELECT "ci_pipelines".* FROM "ci_pipelines" WHERE "ci_pipelines"."id" = 2 LIMIT 1 /*application:test*/
SAVEPOINT active_record_2 /*application:test*/
SELECT "application_settings".* FROM "application_settings" ORDER BY "application_settings"."id" DESC LIMIT 1 /*application:test*/
SELECT "application_settings".* FROM "application_settings" ORDER BY "application_settings"."id" DESC LIMIT 1 /*application:test*/
UPDATE "ci_builds" SET "status" = 'running', "runner_id" = 13, "started_at" = '2021-03-26 04:23:47.882792', "processed" = FALSE, "updated_at" = '2021-03-26 04:23:47.888932', "lock_version" = 1 WHERE "ci_builds"."id" = 5 AND "ci_builds"."lock_version" = 0 /*application:test*/
INSERT INTO "ci_builds_runner_session" ("build_id", "url") VALUES (5, 'https://example.com') RETURNING "id" /*application:test*/
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 5 AND "taggings"."taggable_type" = 'CommitStatus' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) /*application:test*/
SELECT "deployments".* FROM "deployments" WHERE "deployments"."deployable_id" = 5 AND "deployments"."deployable_type" = 'CommitStatus' LIMIT 1 /*application:test*/
SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_runners".* FROM "ci_runners" WHERE "ci_runners"."id" = 13 LIMIT 1 /*application:test*/
UPDATE "ci_builds_metadata" SET "timeout" = 3600, "timeout_source" = 2 WHERE "ci_builds_metadata"."id" = 5 /*application:test*/
RELEASE SAVEPOINT active_record_2 /*application:test*/
SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2 LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 2 AND "routes"."source_type" = 'Project' LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 2 AND "routes"."source_type" = 'Project' LIMIT 1 /*application:test*/
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 4 LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 4 AND "routes"."source_type" = 'Namespace' LIMIT 1 /*application:test*/
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 4 LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 4 AND "routes"."source_type" = 'Namespace' LIMIT 1 /*application:test*/
SELECT "deploy_tokens".* FROM "deploy_tokens" INNER JOIN "project_deploy_tokens" ON "deploy_tokens"."id" = "project_deploy_tokens"."deploy_token_id" WHERE "project_deploy_tokens"."project_id" = 2 AND (revoked = false AND expires_at >= NOW()) AND "deploy_tokens"."name" = 'gitlab-deploy-token' LIMIT 1 /*application:test*/
SELECT "repository_languages".* FROM "repository_languages" WHERE "repository_languages"."project_id" = 2 ORDER BY share DESC /*application:test*/
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 4 AND "namespaces"."type" = 'Group' LIMIT 1 /*application:test*/
SELECT "project_features".* FROM "project_features" WHERE "project_features"."project_id" = 2 LIMIT 1 /*application:test*/
SELECT "project_auto_devops".* FROM "project_auto_devops" WHERE "project_auto_devops"."project_id" = 2 LIMIT 1 /*application:test*/
SELECT 1 AS one FROM "requirements" WHERE "requirements"."project_id" = 2 AND "requirements"."state" = 1 LIMIT 1 /*application:test*/
SELECT "merge_requests".* FROM "merge_requests" WHERE "merge_requests"."source_project_id" = 2 AND "merge_requests"."source_branch" = 'master' AND ("merge_requests"."state_id" IN (1)) ORDER BY "merge_requests"."id" DESC LIMIT 4 /*application:test*/
WITH RECURSIVE "clusters_cte" AS ((SELECT "clusters".*, NULL AS group_parent_id, 0 AS depth FROM "clusters" INNER JOIN "cluster_projects" ON "cluster_projects"."cluster_id" = "clusters"."id" INNER JOIN "projects" ON "projects"."id" = "cluster_projects"."project_id" WHERE "clusters"."management_project_id" = 2 AND "clusters"."cluster_type" = 3 AND "projects"."namespace_id" = 4)
UNION
(SELECT "clusters".*, "projects"."namespace_id" AS group_parent_id, 1 AS depth FROM "projects" LEFT OUTER JOIN "cluster_projects" ON "cluster_projects"."project_id" = "projects"."id" LEFT OUTER JOIN "clusters" ON "clusters"."id" = "cluster_projects"."cluster_id" WHERE "projects"."id" = 2)
UNION
(SELECT "clusters".*, "namespaces"."parent_id" AS group_parent_id, ("clusters_cte"."depth" + 1) FROM "clusters_cte", "namespaces" LEFT OUTER JOIN cluster_groups ON cluster_groups.group_id = namespaces.id LEFT OUTER JOIN clusters ON cluster_groups.cluster_id = clusters.id WHERE "namespaces"."id" = "clusters_cte"."group_parent_id")) SELECT "clusters".* FROM "clusters_cte" "clusters" WHERE (clusters.id IS NOT NULL) AND "clusters"."enabled" = TRUE AND "clusters"."environment_scope" = '*' ORDER BY (CASE clusters.management_project_id
  WHEN 2 THEN 0
  ELSE depth
END) ASC
 LIMIT 1 /*application:test*/
SELECT "clusters".* FROM "clusters" WHERE "clusters"."cluster_type" = 1 AND "clusters"."enabled" = TRUE AND "clusters"."environment_scope" = '*' ORDER BY "clusters"."id" ASC LIMIT 1 /*application:test*/
SELECT "ci_freeze_periods".* FROM "ci_freeze_periods" WHERE "ci_freeze_periods"."project_id" = 2 ORDER BY "ci_freeze_periods"."created_at" ASC /*application:test*/
SELECT "taggings".* FROM "taggings" WHERE "taggings"."taggable_id" = 13 AND "taggings"."taggable_type" = 'Ci::Runner' /*application:test*/
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 13 AND "taggings"."taggable_type" = 'Ci::Runner' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) /*application:test*/
SELECT "ci_builds".* FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND "ci_builds"."commit_id" = 2 AND ("ci_builds"."retried" = FALSE OR "ci_builds"."retried" IS NULL) AND (stage_idx < 0) /*application:test*/
SELECT "ci_instance_variables".* FROM "ci_instance_variables" /*application:test*/
SELECT "ci_variables".* FROM "ci_variables" WHERE "ci_variables"."project_id" = 2 AND "ci_variables"."environment_scope" = '*' /*application:test*/
SELECT "ci_pipeline_variables".* FROM "ci_pipeline_variables" WHERE "ci_pipeline_variables"."pipeline_id" = 2 /*application:test*/
SELECT "ci_job_variables".* FROM "ci_job_variables" WHERE "ci_job_variables"."job_id" = 5 /*application:test*/
SELECT "dast_profiles".* FROM "dast_profiles" INNER JOIN "dast_profiles_pipelines" ON "dast_profiles"."id" = "dast_profiles_pipelines"."dast_profile_id" WHERE "dast_profiles_pipelines"."ci_pipeline_id" = 2 LIMIT 1 /*application:test*/
SELECT "dast_site_profile_secret_variables".* FROM "dast_site_profile_secret_variables" INNER JOIN "dast_site_profiles" ON "dast_site_profile_secret_variables"."dast_site_profile_id" = "dast_site_profiles"."id" WHERE "dast_site_profiles"."id" = 1 /*application:test*/
SELECT "project_ci_cd_settings".* FROM "project_ci_cd_settings" WHERE "project_ci_cd_settings"."project_id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_builds".* FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND "ci_builds"."commit_id" = 2 AND ("ci_builds"."retried" = FALSE OR "ci_builds"."retried" IS NULL) AND (stage_idx < 0) /*application:test*/

After

SELECT "tags"."id" FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 1 AND "taggings"."taggable_type" = 'Ci::Runner' AND "taggings"."context" = 'tags' /*application:test*/
SELECT "ci_builds"."id" FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND ("ci_builds"."status" IN ('pending')) AND "ci_builds"."runner_id" IS NULL AND "ci_builds"."project_id" IN (SELECT "projects"."id" FROM "projects" INNER JOIN "ci_runner_projects" ON "projects"."id" = "ci_runner_projects"."project_id" LEFT JOIN project_features ON projects.id = project_features.project_id WHERE "ci_runner_projects"."runner_id" = 1 AND "projects"."pending_delete" = FALSE AND ("project_features"."builds_access_level" > 0 OR "project_features"."builds_access_level" IS NULL)) AND (NOT EXISTS (SELECT 1 FROM "taggings" WHERE "taggings"."taggable_type" = 'CommitStatus' AND "taggings"."context" = 'tags' AND (taggable_id = ci_builds.id) AND 1=1)) ORDER BY id ASC /*application:test*/
SELECT "ci_builds".* FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND "ci_builds"."id" = 2 LIMIT 1 /*application:test*/
SELECT "taggings".* FROM "taggings" WHERE "taggings"."taggable_id" = 2 AND "taggings"."taggable_type" = 'CommitStatus' /*application:test*/
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 2 AND "taggings"."taggable_type" = 'CommitStatus' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) /*application:test*/
SELECT "ci_builds_runner_session".* FROM "ci_builds_runner_session" WHERE "ci_builds_runner_session"."build_id" = 2 LIMIT 1 /*application:test*/
SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_builds_metadata".* FROM "ci_builds_metadata" WHERE "ci_builds_metadata"."build_id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_pipelines".* FROM "ci_pipelines" WHERE "ci_pipelines"."id" = 2 LIMIT 1 /*application:test*/
SAVEPOINT active_record_2 /*application:test*/
SELECT "application_settings".* FROM "application_settings" ORDER BY "application_settings"."id" DESC LIMIT 1 /*application:test*/
SELECT "application_settings".* FROM "application_settings" ORDER BY "application_settings"."id" DESC LIMIT 1 /*application:test*/
UPDATE "ci_builds" SET "status" = 'running', "runner_id" = 1, "started_at" = '2021-03-26 04:27:11.335162', "processed" = FALSE, "updated_at" = '2021-03-26 04:27:11.343080', "lock_version" = 1 WHERE "ci_builds"."id" = 2 AND "ci_builds"."lock_version" = 0 /*application:test*/
INSERT INTO "ci_builds_runner_session" ("build_id", "url") VALUES (2, 'https://example.com') RETURNING "id" /*application:test*/
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 2 AND "taggings"."taggable_type" = 'CommitStatus' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) /*application:test*/
SELECT "deployments".* FROM "deployments" WHERE "deployments"."deployable_id" = 2 AND "deployments"."deployable_type" = 'CommitStatus' LIMIT 1 /*application:test*/
SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_runners".* FROM "ci_runners" WHERE "ci_runners"."id" = 1 LIMIT 1 /*application:test*/
UPDATE "ci_builds_metadata" SET "timeout" = 3600, "timeout_source" = 2 WHERE "ci_builds_metadata"."id" = 2 /*application:test*/
RELEASE SAVEPOINT active_record_2 /*application:test*/
SELECT "projects".* FROM "projects" WHERE "projects"."id" = 2 LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 2 AND "routes"."source_type" = 'Project' LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 2 AND "routes"."source_type" = 'Project' LIMIT 1 /*application:test*/
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 4 LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 4 AND "routes"."source_type" = 'Namespace' LIMIT 1 /*application:test*/
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 4 LIMIT 1 /*application:test*/
SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 4 AND "routes"."source_type" = 'Namespace' LIMIT 1 /*application:test*/
SELECT "deploy_tokens".* FROM "deploy_tokens" INNER JOIN "project_deploy_tokens" ON "deploy_tokens"."id" = "project_deploy_tokens"."deploy_token_id" WHERE "project_deploy_tokens"."project_id" = 2 AND (revoked = false AND expires_at >= NOW()) AND "deploy_tokens"."name" = 'gitlab-deploy-token' LIMIT 1 /*application:test*/
SELECT "repository_languages".* FROM "repository_languages" WHERE "repository_languages"."project_id" = 2 ORDER BY share DESC /*application:test*/
SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."type" = 'Group' AND "namespaces"."id" = 4 AND "namespaces"."type" = 'Group' LIMIT 1 /*application:test*/
SELECT "project_features".* FROM "project_features" WHERE "project_features"."project_id" = 2 LIMIT 1 /*application:test*/
SELECT "project_auto_devops".* FROM "project_auto_devops" WHERE "project_auto_devops"."project_id" = 2 LIMIT 1 /*application:test*/
SELECT 1 AS one FROM "requirements" WHERE "requirements"."project_id" = 2 AND "requirements"."state" = 1 LIMIT 1 /*application:test*/
SELECT "merge_requests".* FROM "merge_requests" WHERE "merge_requests"."source_project_id" = 2 AND "merge_requests"."source_branch" = 'master' AND ("merge_requests"."state_id" IN (1)) ORDER BY "merge_requests"."id" DESC LIMIT 4 /*application:test*/
WITH RECURSIVE "clusters_cte" AS ((SELECT "clusters".*, NULL AS group_parent_id, 0 AS depth FROM "clusters" INNER JOIN "cluster_projects" ON "cluster_projects"."cluster_id" = "clusters"."id" INNER JOIN "projects" ON "projects"."id" = "cluster_projects"."project_id" WHERE "clusters"."management_project_id" = 2 AND "clusters"."cluster_type" = 3 AND "projects"."namespace_id" = 4)
UNION
(SELECT "clusters".*, "projects"."namespace_id" AS group_parent_id, 1 AS depth FROM "projects" LEFT OUTER JOIN "cluster_projects" ON "cluster_projects"."project_id" = "projects"."id" LEFT OUTER JOIN "clusters" ON "clusters"."id" = "cluster_projects"."cluster_id" WHERE "projects"."id" = 2)
UNION
(SELECT "clusters".*, "namespaces"."parent_id" AS group_parent_id, ("clusters_cte"."depth" + 1) FROM "clusters_cte", "namespaces" LEFT OUTER JOIN cluster_groups ON cluster_groups.group_id = namespaces.id LEFT OUTER JOIN clusters ON cluster_groups.cluster_id = clusters.id WHERE "namespaces"."id" = "clusters_cte"."group_parent_id")) SELECT "clusters".* FROM "clusters_cte" "clusters" WHERE (clusters.id IS NOT NULL) AND "clusters"."enabled" = TRUE AND "clusters"."environment_scope" = '*' ORDER BY (CASE clusters.management_project_id
  WHEN 2 THEN 0
  ELSE depth
END) ASC
 LIMIT 1 /*application:test*/
SELECT "clusters".* FROM "clusters" WHERE "clusters"."cluster_type" = 1 AND "clusters"."enabled" = TRUE AND "clusters"."environment_scope" = '*' ORDER BY "clusters"."id" ASC LIMIT 1 /*application:test*/
SELECT "ci_freeze_periods".* FROM "ci_freeze_periods" WHERE "ci_freeze_periods"."project_id" = 2 ORDER BY "ci_freeze_periods"."created_at" ASC /*application:test*/
SELECT "taggings".* FROM "taggings" WHERE "taggings"."taggable_id" = 1 AND "taggings"."taggable_type" = 'Ci::Runner' /*application:test*/
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 1 AND "taggings"."taggable_type" = 'Ci::Runner' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) /*application:test*/
SELECT "ci_builds".* FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND "ci_builds"."commit_id" = 2 AND ("ci_builds"."retried" = FALSE OR "ci_builds"."retried" IS NULL) AND (stage_idx < 0) /*application:test*/
SELECT "ci_instance_variables".* FROM "ci_instance_variables" /*application:test*/
SELECT "ci_variables".* FROM "ci_variables" WHERE "ci_variables"."project_id" = 2 AND "ci_variables"."environment_scope" = '*' /*application:test*/
SELECT "ci_pipeline_variables".* FROM "ci_pipeline_variables" WHERE "ci_pipeline_variables"."pipeline_id" = 2 /*application:test*/
SELECT "ci_job_variables".* FROM "ci_job_variables" WHERE "ci_job_variables"."job_id" = 2 /*application:test*/
SELECT "dast_profiles".* FROM "dast_profiles" INNER JOIN "dast_profiles_pipelines" ON "dast_profiles"."id" = "dast_profiles_pipelines"."dast_profile_id" WHERE "dast_profiles_pipelines"."ci_pipeline_id" = 2 LIMIT 1 /*application:test*/
SELECT "dast_site_profile_secret_variables".* FROM "dast_site_profile_secret_variables" INNER JOIN "dast_site_profiles" ON "dast_site_profile_secret_variables"."dast_site_profile_id" = "dast_site_profiles"."id" WHERE "dast_site_profiles"."id" = 1 /*application:test*/
SELECT "project_ci_cd_settings".* FROM "project_ci_cd_settings" WHERE "project_ci_cd_settings"."project_id" = 2 LIMIT 1 /*application:test*/
SELECT "ci_builds".* FROM "ci_builds" WHERE "ci_builds"."type" = 'Ci::Build' AND "ci_builds"."commit_id" = 2 AND ("ci_builds"."retried" = FALSE OR "ci_builds"."retried" IS NULL) AND (stage_idx < 0) /*application:test*/

Delta

additional queries:

SELECT "dast_profiles".* FROM "dast_profiles" INNER JOIN "dast_profiles_pipelines" ON "dast_profiles"."id" = "dast_profiles_pipelines"."dast_profile_id" WHERE "dast_profiles_pipelines"."ci_pipeline_id" = 2 LIMIT 1
SELECT "dast_site_profile_secret_variables".* FROM "dast_site_profile_secret_variables" INNER JOIN "dast_site_profiles" ON "dast_site_profile_secret_variables"."dast_site_profile_id" = "dast_site_profiles"."id" WHERE "dast_site_profiles"."id" = 1

Analysis

SELECT "dast_profiles".* FROM "dast_profiles" INNER JOIN "dast_profiles_pipelines" ON "dast_profiles"."id" = "dast_profiles_pipelines"."dast_profile_id" WHERE "dast_profiles_pipelines"."ci_pipeline_id" = 2 LIMIT 1

Limit  (cost=0.30..4.34 rows=1 width=144) (actual time=0.014..0.014 rows=1 loops=1)
  ->  Nested Loop  (cost=0.30..4.34 rows=1 width=144) (actual time=0.013..0.014 rows=1 loops=1)
        ->  Index Scan using index_dast_profiles_pipelines_on_ci_pipeline_id on dast_profiles_pipelines  (cost=0.15..2.17 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=1)
              Index Cond: (ci_pipeline_id = 2)
        ->  Index Scan using dast_profiles_pkey on dast_profiles  (cost=0.15..2.17 rows=1 width=144) (actual time=0.003..0.003 rows=1 loops=1)
              Index Cond: (id = dast_profiles_pipelines.dast_profile_id)

Planning Time: 0.136 ms
Execution Time: 0.032 ms

https://explain.depesz.com/s/Y6YA

SELECT "dast_site_profile_secret_variables".* FROM "dast_site_profile_secret_variables" INNER JOIN "dast_site_profiles" ON "dast_site_profile_secret_variables"."dast_site_profile_id" = "dast_site_profiles"."id" WHERE "dast_site_profiles"."id" = 1

Nested Loop  (cost=0.29..6.40 rows=3 width=130) (actual time=0.014..0.015 rows=1 loops=1)
  ->  Index Only Scan using dast_site_profiles_pkey on dast_site_profiles  (cost=0.15..2.17 rows=1 width=8) (actual time=0.009..0.009 rows=1 loops=1)
        Index Cond: (id = 1)
        Heap Fetches: 1
  ->  Index Scan using index_site_profile_secret_variables_on_site_profile_id_and_key on dast_site_profile_secret_variables  (cost=0.15..4.20 rows=3 width=130) (actual time=0.003..0.003 rows=1 loops=1)
        Index Cond: (dast_site_profile_id = 1)

Planning Time: 0.092 ms
Execution Time: 0.031 ms

https://explain.depesz.com/s/eFKY

Screenshots

what the build log looks like when a dast_site_profile_secret_variable is provided (HELLO_WORLD_BASE64):

image

^ manual quality assurance through creating a dast_profile and creating associated dast_site_profile_secret_variable in the console.

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • Label as security and @ mention @gitlab-com/gl-security/appsec
  • The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • Security reports checked/validated by a reviewer from the AppSec team
Edited by Mayra Cabrera

Merge request reports