gitlab-qa 15.7.2 → 15.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +0 -1
- data/Gemfile.lock +1 -1
- data/docs/what_tests_can_be_run.md +16 -28
- data/lib/gitlab/qa/component/duo_workflow_service.rb +83 -0
- data/lib/gitlab/qa/scenario/test/integration/ai_gateway_base.rb +40 -3
- data/lib/gitlab/qa/scenario/test/integration/duo_agent_platform.rb +26 -0
- data/lib/gitlab/qa/version.rb +1 -1
- metadata +4 -3
- data/lib/gitlab/qa/scenario/test/integration/mattermost.rb +0 -41
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f712be690928e97a469fb1845b7032a8064df288ea7110c98aa782a01c84a41
|
|
4
|
+
data.tar.gz: df0a1fc951cacee6d314fcbdc9e02b1b7e7628d8ae489807a42a1b8713bbb3b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 057716e20ffafc661fdb6489dc7f23cdb57252f097b8b9c6cf55f62dadcf326140d3725010418c3121f403771779b9ebd8b7f4df290030dd6a906b372df05dc7
|
|
7
|
+
data.tar.gz: 660b043282d0d028ea8790c52ec10f0696c1236a15533e469b7514355bfba98f1870144c08b682b40a720464cc1153b5d0a69ca5f75a4f3651920454aabcda81
|
data/.rubocop_todo.yml
CHANGED
|
@@ -45,7 +45,6 @@ Metrics/AbcSize:
|
|
|
45
45
|
- 'lib/gitlab/qa/scenario/test/integration/gitlab_pages.rb'
|
|
46
46
|
- 'lib/gitlab/qa/scenario/test/integration/integrations.rb'
|
|
47
47
|
- 'lib/gitlab/qa/scenario/test/integration/jira.rb'
|
|
48
|
-
- 'lib/gitlab/qa/scenario/test/integration/mattermost.rb'
|
|
49
48
|
- 'lib/gitlab/qa/scenario/test/integration/metrics.rb'
|
|
50
49
|
- 'lib/gitlab/qa/scenario/test/integration/mtls.rb'
|
|
51
50
|
- 'lib/gitlab/qa/scenario/test/integration/oauth.rb'
|
data/Gemfile.lock
CHANGED
|
@@ -640,34 +640,6 @@ $ export EE_LICENSE=$(cat /path/to/gitlab_license)
|
|
|
640
640
|
$ gitlab-qa Test::Integration::OAuth EE
|
|
641
641
|
```
|
|
642
642
|
|
|
643
|
-
### `Test::Integration::Mattermost CE|EE|<full image address>`
|
|
644
|
-
|
|
645
|
-
This tests that a GitLab instance works as expected when enabling the embedded
|
|
646
|
-
Mattermost server (see `Test::Instance::Image` above).
|
|
647
|
-
|
|
648
|
-
To run tests against the GitLab container, a GitLab QA (`gitlab/gitlab-qa`)
|
|
649
|
-
container is spun up and tests are run from it by running the
|
|
650
|
-
`Test::Integration::Mattermost` scenario (located under
|
|
651
|
-
[`gitlab-org/gitlab/qa/qa/scenario/test/integration/mattermost.rb`][test-integration-mattermost]
|
|
652
|
-
in the GitLab project).
|
|
653
|
-
|
|
654
|
-
**Required environment variables:**
|
|
655
|
-
|
|
656
|
-
- [For EE only] `EE_LICENSE`: A valid EE license.
|
|
657
|
-
|
|
658
|
-
Example:
|
|
659
|
-
|
|
660
|
-
```shell
|
|
661
|
-
$ gitlab-qa Test::Integration::Mattermost CE
|
|
662
|
-
|
|
663
|
-
# For EE
|
|
664
|
-
$ export EE_LICENSE=$(cat /path/to/Geo.gitlab_license)
|
|
665
|
-
|
|
666
|
-
$ gitlab-qa Test::Integration::Mattermost EE
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
[test-integration-mattermost]: https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/scenario/test/integration/mattermost.rb
|
|
670
|
-
|
|
671
643
|
### `Test::Integration::Packages CE|EE|<full image address>`
|
|
672
644
|
|
|
673
645
|
**Note: This Scenario no longer exists. See https://gitlab.com/gitlab-org/gitlab-qa/-/merge_requests/662**
|
|
@@ -1239,6 +1211,7 @@ $ export GITLAB_LICENSE_MODE="test"
|
|
|
1239
1211
|
|
|
1240
1212
|
- Runs tests tagged with `:ai_gateway`
|
|
1241
1213
|
- GitLab instance has a cloud license with either a Duo Pro add-on or Duo Enterprise add-on, and a seat is assigned to the admin user. Choose Duo Enterprise over Duo Pro when available.
|
|
1214
|
+
- Serves the Duo Chat and Code Suggestions feature areas. It does not boot the Duo Workflow Service (DWS); the Duo Agent Platform foundational flow runs under the dedicated `Test::Integration::DuoAgentPlatform` scenario (below).
|
|
1242
1215
|
|
|
1243
1216
|
Example:
|
|
1244
1217
|
|
|
@@ -1248,6 +1221,21 @@ $ gitlab-qa Test::Integration::AiGateway EE
|
|
|
1248
1221
|
|
|
1249
1222
|
----
|
|
1250
1223
|
|
|
1224
|
+
#### `Test::Integration::DuoAgentPlatform EE|<full image address>`
|
|
1225
|
+
|
|
1226
|
+
- Runs tests tagged with `:duo_agent_platform`
|
|
1227
|
+
- Subclass of `Test::Integration::AiGateway`, so it inherits the same setup (cloud license + Duo add-on + assigned seat, plus the mock AI Gateway).
|
|
1228
|
+
- In addition, this scenario boots a mock Duo Workflow Service (DWS) container in agentic-mock mode (`duo-workflow-service`, from the same `model-gateway` image switched to the DWS gRPC server) and points GitLab at it via the `GITLAB_DUO_WORKFLOW_SERVICE_URL` / `GITLAB_DUO_WORKFLOW_SECURE` environment variables. This lets the Duo Agent Platform foundational-flow spec drive a flow end-to-end without a real LLM.
|
|
1229
|
+
- DWS container logs are captured to the job artifacts (`duo-workflow-service/logs/duo-workflow-service.log`) on teardown.
|
|
1230
|
+
|
|
1231
|
+
Example:
|
|
1232
|
+
|
|
1233
|
+
```shell
|
|
1234
|
+
$ gitlab-qa Test::Integration::DuoAgentPlatform EE
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
----
|
|
1238
|
+
|
|
1251
1239
|
#### `Test::Integration::AiGatewayNoSeatAssigned EE|<full image address>`
|
|
1252
1240
|
|
|
1253
1241
|
- Runs tests tagged with `:ai_gateway_no_seat_assigned`
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module QA
|
|
7
|
+
module Component
|
|
8
|
+
# Boots the Duo Workflow Service (DWS) gRPC server in agentic-mock mode for Duo Agent
|
|
9
|
+
# Platform foundational-flow E2E tests. DWS ships inside the same model-gateway image as
|
|
10
|
+
# the AI Gateway; we reuse that image and switch the container to the DWS server via
|
|
11
|
+
# ENABLE_DUO_WORKFLOW_SERVICE / DISABLE_AI_GATEWAY (handled by the image's scripts/run.sh).
|
|
12
|
+
class DuoWorkflowService < Base
|
|
13
|
+
# Same artifact as the AI Gateway container, so the agentic mock model and DWS agree.
|
|
14
|
+
DOCKER_IMAGE = AiGateway::DOCKER_IMAGE
|
|
15
|
+
DOCKER_IMAGE_TAG = AiGateway::DOCKER_IMAGE_TAG
|
|
16
|
+
|
|
17
|
+
GRPC_PORT = 50052
|
|
18
|
+
LOG_FILE_NAME = 'duo-workflow-service.log'
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
super
|
|
22
|
+
|
|
23
|
+
@secrets << AiGateway::TEST_SIGNING_KEY
|
|
24
|
+
@secrets << AiGateway::TEST_VALIDATION_KEY
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def name
|
|
28
|
+
@name ||= 'duo-workflow-service'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def configure_environment(gitlab_hostname:)
|
|
32
|
+
@environment = {
|
|
33
|
+
# Switch the shared image from the AIGW FastAPI app to the DWS gRPC server.
|
|
34
|
+
'ENABLE_DUO_WORKFLOW_SERVICE' => true,
|
|
35
|
+
'DISABLE_AI_GATEWAY' => true,
|
|
36
|
+
'PORT' => GRPC_PORT,
|
|
37
|
+
|
|
38
|
+
# Agentic mock: select the deterministic in-process mock model. With both flags set,
|
|
39
|
+
# DWS makes no real LLM/AIGW call; the goal's <response>/<tool_calls> directives drive it.
|
|
40
|
+
'AIGW_MOCK_MODEL_RESPONSES' => true,
|
|
41
|
+
'AIGW_USE_AGENTIC_MOCK' => true,
|
|
42
|
+
|
|
43
|
+
# Disable DWS auth: with auth ENABLED, DWS prefetches JWKS from GitLab + CustomersDot
|
|
44
|
+
# at startup and hard-fails if unreachable (bad in a sealed CI network). Disabling
|
|
45
|
+
# skips that prefetch and bypasses ExecuteWorkflow token validation.
|
|
46
|
+
'DUO_WORKFLOW_AUTH__ENABLED' => false,
|
|
47
|
+
|
|
48
|
+
# ...but Rails still calls the GenerateToken RPC first, which needs the signing key
|
|
49
|
+
# present or the encode fails. So supply the DWS-prefixed self-signed keypair.
|
|
50
|
+
'DUO_WORKFLOW_SELF_SIGNED_JWT__SIGNING_KEY' => AiGateway::TEST_SIGNING_KEY,
|
|
51
|
+
'DUO_WORKFLOW_SELF_SIGNED_JWT__VALIDATION_KEY' => AiGateway::TEST_VALIDATION_KEY,
|
|
52
|
+
|
|
53
|
+
# Falls back to AIGW_GITLAB_URL if unset; set both for consistency.
|
|
54
|
+
'DUO_WORKFLOW_AUTH__OIDC_GITLAB_URL' => "http://#{gitlab_hostname}",
|
|
55
|
+
'AIGW_GITLAB_URL' => "http://#{gitlab_hostname}"
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# DWS logs to stdout/stderr and writes no in-container log file (unlike the AI Gateway),
|
|
60
|
+
# so capture `docker logs` into the host artifacts directory before the container is
|
|
61
|
+
# force-removed on teardown. Without this the DWS logs are lost on removal.
|
|
62
|
+
def teardown
|
|
63
|
+
capture_logs
|
|
64
|
+
ensure
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def host_log_path
|
|
71
|
+
File.join(Runtime::Env.host_artifacts_dir, name, 'logs', LOG_FILE_NAME)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def capture_logs
|
|
75
|
+
FileUtils.mkdir_p(File.dirname(host_log_path))
|
|
76
|
+
File.write(host_log_path, Docker::Command.execute("logs #{name}", mask_secrets: @secrets))
|
|
77
|
+
rescue Support::ShellCommand::StatusError, SystemCallError => e
|
|
78
|
+
Runtime::Logger.warn("Unable to capture logs from #{name}: #{e.message}")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -14,6 +14,10 @@ module Gitlab
|
|
|
14
14
|
@ai_gateway_name = 'ai-gateway'
|
|
15
15
|
@ai_gateway_hostname = "#{@ai_gateway_name}.#{@network}"
|
|
16
16
|
@ai_gateway_port = 5000
|
|
17
|
+
@dws_name = 'duo-workflow-service'
|
|
18
|
+
@dws_hostname = "#{@dws_name}.#{@network}"
|
|
19
|
+
@dws_port = Component::DuoWorkflowService::GRPC_PORT
|
|
20
|
+
@boot_duo_workflow_service = false
|
|
17
21
|
@use_cloud_license = true
|
|
18
22
|
@has_add_on = true
|
|
19
23
|
@assign_seats = true
|
|
@@ -27,15 +31,31 @@ module Gitlab
|
|
|
27
31
|
set_up_ai_gateway(ai_gateway, gitlab_hostname: gitlab.hostname)
|
|
28
32
|
|
|
29
33
|
ai_gateway.instance do
|
|
30
|
-
gitlab.
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
with_duo_workflow_service(gitlab_hostname: gitlab.hostname) do
|
|
35
|
+
gitlab.instance do
|
|
36
|
+
set_up_gitlab_duo(gitlab) if @use_cloud_license
|
|
37
|
+
run_specs(gitlab, *rspec_args)
|
|
38
|
+
end
|
|
33
39
|
end
|
|
34
40
|
end
|
|
35
41
|
end
|
|
36
42
|
end
|
|
37
43
|
end
|
|
38
44
|
|
|
45
|
+
# Boots the agentic-mock Duo Workflow Service alongside the AI Gateway and runs the
|
|
46
|
+
# given block inside it. When @boot_duo_workflow_service is false (the default for
|
|
47
|
+
# AiGateway and the No*/NoLicense variants) it is a no-op passthrough, so only the
|
|
48
|
+
# DuoAgentPlatform scenario has the extra gRPC container.
|
|
49
|
+
def with_duo_workflow_service(gitlab_hostname:, &block)
|
|
50
|
+
return yield unless @boot_duo_workflow_service
|
|
51
|
+
|
|
52
|
+
Component::DuoWorkflowService.perform do |dws|
|
|
53
|
+
set_up_duo_workflow_service(dws, gitlab_hostname: gitlab_hostname)
|
|
54
|
+
|
|
55
|
+
dws.instance(&block)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
39
59
|
def set_up_gitlab(gitlab, release)
|
|
40
60
|
gitlab.release = QA::Release.new(release)
|
|
41
61
|
gitlab.name = 'gitlab'
|
|
@@ -44,6 +64,15 @@ module Gitlab
|
|
|
44
64
|
gitlab.omnibus_gitlab_rails_env['AI_GATEWAY_URL'] = "http://#{@ai_gateway_hostname}:#{@ai_gateway_port}"
|
|
45
65
|
gitlab.omnibus_gitlab_rails_env['LLM_DEBUG'] = 'true'
|
|
46
66
|
|
|
67
|
+
if @boot_duo_workflow_service
|
|
68
|
+
# Point the foundational-flow path at the in-network agentic-mock DWS, plaintext.
|
|
69
|
+
# These are read by config/initializers/1_settings.rb (duo_workflow.service_url /
|
|
70
|
+
# .secure); the value is a bare gRPC host:port (no scheme), and 'false' is parsed
|
|
71
|
+
# via Gitlab::Utils.to_boolean.
|
|
72
|
+
gitlab.omnibus_gitlab_rails_env['GITLAB_DUO_WORKFLOW_SERVICE_URL'] = "#{@dws_hostname}:#{@dws_port}"
|
|
73
|
+
gitlab.omnibus_gitlab_rails_env['GITLAB_DUO_WORKFLOW_SECURE'] = 'false'
|
|
74
|
+
end
|
|
75
|
+
|
|
47
76
|
gitlab.set_ee_activation_code if @use_cloud_license
|
|
48
77
|
end
|
|
49
78
|
|
|
@@ -55,6 +84,14 @@ module Gitlab
|
|
|
55
84
|
ai_gateway.configure_environment(gitlab_hostname: gitlab_hostname)
|
|
56
85
|
end
|
|
57
86
|
|
|
87
|
+
def set_up_duo_workflow_service(dws, gitlab_hostname:)
|
|
88
|
+
dws.name = @dws_name
|
|
89
|
+
dws.network = @network
|
|
90
|
+
dws.ports = [@dws_port]
|
|
91
|
+
|
|
92
|
+
dws.configure_environment(gitlab_hostname: gitlab_hostname)
|
|
93
|
+
end
|
|
94
|
+
|
|
58
95
|
def set_up_gitlab_duo(gitlab)
|
|
59
96
|
Runtime::Logger.info('Setting up Gitlab Duo on GitLab instance')
|
|
60
97
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module QA
|
|
5
|
+
module Scenario
|
|
6
|
+
module Test
|
|
7
|
+
module Integration
|
|
8
|
+
# Duo Agent Platform foundational-flow smoke scenario. Reuses the AiGateway scenario's
|
|
9
|
+
# setup (EE omnibus GitLab + mock AI Gateway) and additionally boots the agentic-mock
|
|
10
|
+
# Duo Workflow Service, running under its own tag so the foundational flow gets a
|
|
11
|
+
# dedicated omnibus job, separate from the ai-gateway job (Duo Chat / Code Suggestions).
|
|
12
|
+
class DuoAgentPlatform < AiGateway
|
|
13
|
+
def initialize
|
|
14
|
+
super
|
|
15
|
+
@tag = 'duo_agent_platform'
|
|
16
|
+
# Only the DAP foundational flow needs the Duo Workflow Service; the ai-gateway
|
|
17
|
+
# job (Duo Chat / Code Suggestions) does not, so boot DWS here rather than on the
|
|
18
|
+
# base AiGateway scenario.
|
|
19
|
+
@boot_duo_workflow_service = true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/gitlab/qa/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-qa
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 15.
|
|
4
|
+
version: 15.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitLab Quality
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: climate_control
|
|
@@ -403,6 +403,7 @@ files:
|
|
|
403
403
|
- lib/gitlab/qa/component/alpine.rb
|
|
404
404
|
- lib/gitlab/qa/component/base.rb
|
|
405
405
|
- lib/gitlab/qa/component/chaos.rb
|
|
406
|
+
- lib/gitlab/qa/component/duo_workflow_service.rb
|
|
406
407
|
- lib/gitlab/qa/component/elasticsearch.rb
|
|
407
408
|
- lib/gitlab/qa/component/gitaly.rb
|
|
408
409
|
- lib/gitlab/qa/component/gitaly_cluster.rb
|
|
@@ -470,6 +471,7 @@ files:
|
|
|
470
471
|
- lib/gitlab/qa/scenario/test/integration/chaos.rb
|
|
471
472
|
- lib/gitlab/qa/scenario/test/integration/client_ssl.rb
|
|
472
473
|
- lib/gitlab/qa/scenario/test/integration/continuous_vulnerability_scanning.rb
|
|
474
|
+
- lib/gitlab/qa/scenario/test/integration/duo_agent_platform.rb
|
|
473
475
|
- lib/gitlab/qa/scenario/test/integration/elasticsearch.rb
|
|
474
476
|
- lib/gitlab/qa/scenario/test/integration/geo.rb
|
|
475
477
|
- lib/gitlab/qa/scenario/test/integration/gitaly_cluster.rb
|
|
@@ -484,7 +486,6 @@ files:
|
|
|
484
486
|
- lib/gitlab/qa/scenario/test/integration/ldap_no_server.rb
|
|
485
487
|
- lib/gitlab/qa/scenario/test/integration/ldap_no_tls.rb
|
|
486
488
|
- lib/gitlab/qa/scenario/test/integration/ldap_tls.rb
|
|
487
|
-
- lib/gitlab/qa/scenario/test/integration/mattermost.rb
|
|
488
489
|
- lib/gitlab/qa/scenario/test/integration/metrics.rb
|
|
489
490
|
- lib/gitlab/qa/scenario/test/integration/mtls.rb
|
|
490
491
|
- lib/gitlab/qa/scenario/test/integration/opensearch.rb
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Gitlab
|
|
4
|
-
module QA
|
|
5
|
-
module Scenario
|
|
6
|
-
module Test
|
|
7
|
-
module Integration
|
|
8
|
-
class Mattermost < Scenario::Template
|
|
9
|
-
def perform(release, *rspec_args)
|
|
10
|
-
Component::Gitlab.perform do |gitlab|
|
|
11
|
-
gitlab.release = release
|
|
12
|
-
gitlab.network = Runtime::Env.docker_network
|
|
13
|
-
|
|
14
|
-
mattermost_hostname = "mattermost.#{gitlab.network}"
|
|
15
|
-
mattermost_external_url = "http://#{mattermost_hostname}"
|
|
16
|
-
|
|
17
|
-
gitlab.add_network_alias(mattermost_hostname)
|
|
18
|
-
gitlab.omnibus_configuration << <<~OMNIBUS
|
|
19
|
-
mattermost_external_url '#{mattermost_external_url}';
|
|
20
|
-
OMNIBUS
|
|
21
|
-
|
|
22
|
-
gitlab.instance do
|
|
23
|
-
Component::Specs.perform do |specs|
|
|
24
|
-
specs.suite = 'Test::Integration::Mattermost'
|
|
25
|
-
specs.release = gitlab.release
|
|
26
|
-
specs.network = gitlab.network
|
|
27
|
-
specs.args = [
|
|
28
|
-
gitlab.address,
|
|
29
|
-
"--mattermost-address", mattermost_external_url,
|
|
30
|
-
*rspec_args
|
|
31
|
-
]
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|