Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -198,5 +198,16 @@ tags
# Persistent undo
[._]*.un~

**/exploit-iq-ips.json
**/user-feedback-ips.json
**/google-sheets-secrets.yaml
**/integration-tests-secrets.yaml
**/server-model-config.yaml
**/sec-decryption.key
**/registry-app-creds.yaml
**/exploit-iq-client-build-ips.yaml
**/exploit-iq-automation-token.yaml



# End of https://www.gitignore.io/api/vim,c++,cmake,python,synology
5 changes: 5 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
[submodule ".tests-automation"]
path = .tests-automation
url = https://github.com/RHEcosystemAppEng/exploitiq-tests-automation.git

[submodule "exploit-iq-models"]
path = exploit-iq-models
url = https://github.com/RHEcosystemAppEng/exploit-iq-models.git

9 changes: 7 additions & 2 deletions .tekton/on-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ metadata:
# How many runs we want to keep.
pipelinesascode.tekton.dev/max-keep-runs: "5"
spec:
taskRunTemplate:
podTemplate:
imagePullSecrets:
- name: ecosystem-appeng-morpheus-quay
params:
# The variable with brackets are special to Pipelines as Code
# They will automatically be expanded with the events from Github.
Expand Down Expand Up @@ -241,7 +245,6 @@ spec:
# This is handled in the Makefile's lint-pr target and should be reverted after migration.
make lint-pr TARGET_BRANCH=$TARGET_BRANCH_NAME


print_banner "RUNNING UNIT TESTS"
make test-unit PYTEST_OPTS="--log-cli-level=DEBUG"

Expand All @@ -257,6 +260,8 @@ spec:
workspace: basic-auth # Needed for pushing tags/releases
- name: exploit-iq-data
workspace: exploit-iq-data
- name: dockerconfig
workspace: dockerconfig-ws
params:
- name: CURRENT_REVISION
value: $(params.revision)
Expand Down Expand Up @@ -452,7 +457,7 @@ spec:
echo "--- STARTING INTEGRATION TESTS ---"
echo "--- DEBUG: Current Directory ---"
pwd
echo " -- check it certificate is mounted"
echo " -- check if certificate is mounted"
ls -l /app/certs/service-ca.crt
# 2. Prepares the IT input for test
cp -f ci/it/integration-tests-input.json /app/src/input/scan_it.json
Expand Down
115 changes: 113 additions & 2 deletions kustomize/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ EOF

6. Create the `oauth-secret.env` file containing the `client-secret` and `openshift-domain` values required by the [ExploitIQ Client](./base/exploit_iq_client.yaml) configuration.

Replace `some-long-secret-used-by-the-oauth-client` with a more secure, unique secret
If openshift resource of kind `OAuthClient` named `exploit-iq-client` exists, just get the secret from there:
```shell
export OAUTH_CLIENT_SECRET=$(oc get oauthclient exploit-iq-client -o jsonpath='{..secret}')
```
Otherwise, Replace `some-long-secret-used-by-the-oauth-client` with a more secure, unique secret of your own:

```shell
export OAUTH_CLIENT_SECRET="some-long-secret-used-by-the-oauth-client"
Expand Down Expand Up @@ -257,7 +261,7 @@ redirectURIs:
- "http://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')"
EOF
```
Otherwise, just add your route to the existing `OAuthClient` CR object:
Otherwise ( if creating `OAuthClient` instance got error because it's already exists in the cluster), just add your route to the existing `OAuthClient` CR object:
```shell
export HTTPS_ROUTE=https://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')
export HTTP_ROUTE=http://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')
Expand Down Expand Up @@ -286,3 +290,110 @@ kustomize build overlays/$DEPLOYMENT_VARIANT_NAME/ | oc delete -l purpose!=pers
# Or, Delete Everything
kustomize build overlays/$DEPLOYMENT_VARIANT_NAME/ | oc delete -f -
```
### Deploy Test overlay variant (Rapid deployment)
1. Download and install [GnuPG](https://www.gnupg.org/download/) and [sops](https://github.com/getsops/sops/releases)
2. Create new namespace/project:
```shell
export PROJECT_NAME=exploit-test
oc new-project $PROJECT_NAME
```
3. Take private key from vault ( `ExploitIQ Tests Deployment Variant Private Key for Decryption.`) and import it to GPG:
```shell
gpg --import /path/to/sec-decryption.key
```
4. Decrypt all secret files:
```shell
cd $(git rev-parse --show-toplevel)/kustomize/overlays/tests
mkdir -p secrets
sops -d exploit-iq-ips.secret > secrets/exploit-iq-ips.json
sops -d google-sheets-secrets-enc.yaml > secrets/google-sheets-secrets.yaml
sops -d integration-tests-secrets-enc.yaml > secrets/integration-tests-secrets.yaml
sops -d mongodb-credentials.env2 > secrets/mongodb-credentials.env
sops -d oauth-secrets.env2 > secrets/oauth-secrets.env
sops -d registry-app-creds-enc.yaml > secrets/registry-app-creds.yaml
sops -d secrets.env2 > secrets/secrets.env
sops -d server-model-config-enc.yaml > secrets/server-model-config.yaml
sops -d user-feedback-ips.secret > secrets/user-feedback-ips.json
sops -d exploit-iq-client-build-ips-enc.yaml > secrets/exploit-iq-client-build-ips.yaml
sops -d exploit-iq-automation-token-enc.yaml > secrets/exploit-iq-automation-token.yaml
```

5. Override any secret that you need in the decrypted files, if not needed, you can continue to next step.

>[!WARNING]
Without completing the following step with the correct secret from step 6, authentication and logging into the UI App will fail!

6. If openshift resource of kind `OAuthClient` named `exploit-iq-client` exists, just get the secret from there:
```shell
export OAUTH_CLIENT_SECRET=$(oc get oauthclient exploit-iq-client -o jsonpath='{..secret}')
echo oauthClientSecret=$OAUTH_CLIENT_SECRET
```
Otherwise, Replace `some-long-secret-used-by-the-oauth-client` with a more secure, unique secret of your own:

```shell
export OAUTH_CLIENT_SECRET="some-long-secret-used-by-the-oauth-client"
```
Eventually, Run the following:
```shell
cat > secrets/oauth-secrets.env << EOF
client-secret=$OAUTH_CLIENT_SECRET
openshift-domain=$(oc get dns cluster -o jsonpath='{.spec.baseDomain}')
EOF
```

7. Update `ExploitIQ` configuration file with the correct callback URL for the client service
```shell
cd $(git rev-parse --show-toplevel)/kustomize
export CALLBACK_URL="https://exploit-iq-client.$(oc project -q).svc:8443"
find . -type f -name 'exploit-iq-config.yml' -exec sed -i "s|CALLBACK_URL_PLACEHOLDER|$CALLBACK_URL|g" {} +
cd $(git rev-parse --show-toplevel)/kustomize/overlays/tests
```

8. Now deploy to the cluster the exploitIQ system ( minus agent) with all resources:
```shell
kustomize build . | oc apply -f -
```


9. If it doesn't already exist, create the `OAuthClient` Custom Resource using the secret (from step 6) and generated route

```bash
oc create -f - <<EOF
apiVersion: oauth.openshift.io/v1
kind: OAuthClient
metadata:
name: exploit-iq-client
grantMethod: prompt
secret: $OAUTH_CLIENT_SECRET
redirectURIs:
- "http://exploit-iq-client:8080"
- "https://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')"
- "http://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')"
EOF
```
Otherwise ( if creating `OAuthClient` instance got error because it's already exists in the cluster), just add your route to the existing `OAuthClient` CR object:
```shell
export HTTPS_ROUTE=https://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')
export HTTP_ROUTE=http://$(oc get route exploit-iq-client -o jsonpath='{.spec.host}')
oc patch oauthclient exploit-iq-client -p '{"redirectURIs":["'$HTTP_ROUTE'","'$HTTPS_ROUTE'"]}'
```

10. Deploy Self hosted LLM for the automation tests ( Integration tests and Confusion matrix runner):
```shell
helm upgrade --install --set nim_embed.enabled=false --set llama3_1_70b_instruct_4bit.storageClass.name=gp3-csi-throughput-2000 --set llama3_1_70b_instruct_4bit.readinessProbe.initialDelaySeconds=25 --set llama3_1_70b_instruct_4bit.readinessProbe.periodSeconds=10 --set global.tolerationsKey=p4d-gpu exploit-iq-tests ../../../exploit-iq-models/agent-morpheus-models
```

11. Remove untracked decrypted secrets files
```shell
rm -rf secrets/
```

12. Tear down:
```shell
helm delete exploit-iq-tests

oc delete project $(oc project --short -q)
```

13. Need to install on cluster [Openshift pipelines operator](https://docs.redhat.com/en/documentation/red_hat_openshift_pipelines/1.19/html/installing_and_configuring/installing-pipelines)If need to install the [exploit-iq-pac](https://github.com/apps/exploit-iq-pac/) PAC (pipeline as code) github application on a new cluster , you need to make sure to configure it according to the [PAC github application docs](https://pipelinesascode.com/docs/install/github_apps/#configure-pipelines-as-code-on-your-cluster-to-access-the-github-app).
In this case, you need to supply to the secret in the documentation github application private key generated in the github app settings, and webhook secret defined and set it in the github application settings.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ apiVersion: tekton.dev/v1
kind: Task
metadata:
name: buildah-pvc
namespace: ruben-morpheus

spec:
description: |
Expand Down Expand Up @@ -165,4 +164,4 @@ spec:
- description: An optional workspace that allows providing the entitlement keys for Buildah to access subscription. The mounted workspace contains entitlement.pem and entitlement-key.pem.
mountPath: /tmp/entitlement
name: rhel-entitlement
optional: true
optional: true
24 changes: 24 additions & 0 deletions kustomize/overlays/tests/exploit-iq-automation-token-enc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: ENC[AES256_GCM,data:Uns=,iv:t7ZWH0eiE63kyMW42wFsfsKN01OkC+brLLXaJUEClQs=,tag:pxTCqrwC1cUO/EMTfFrPzA==,type:str]
data:
gh-token: ENC[AES256_GCM,data:GgFKPuhztlsqsZ7PjXGH6V04uNu6ElKs5iC8uUW/UCL7vjmx5VR0suUaDA1DISb+Bc9W83bMnkW70H8CUwMX50OI536T/hDTokLAYTsFD+05HsUWKSxBqq7G25fv3mzPYSBAVKs0EL7K+f2Le6k2yeYltkOkfIRFtabFcg==,iv:cl5jl1oKbR2AtJYCoH4Je8SSyP4Jc+gPInIRfOflTSw=,tag:CrnZspbYfUjz0wgjzwfQhg==,type:str]
kind: ENC[AES256_GCM,data:j8rCiStt,iv:CaoFjqicLryq3MS+mvgVO5ffBbIX9vUQVQ5uy/NyNnM=,tag:r4LeUOBMkvXK3hd7faj/wA==,type:str]
metadata:
name: ENC[AES256_GCM,data:X7/gU5Es3+keADmoDJQWfF27KBKVjoCUcLRe,iv:zYPeX1H91bcUut1/wbVi6UdyRAwcT2QKRu//GS8KAY0=,tag:hPQtbwjqeIazh/hrnmzbjA==,type:str]
type: ENC[AES256_GCM,data:waF5cqrS,iv:yh5grziLkmXblL+zoo/DbsFI8GJdBICWq5xbGrjqrjM=,tag:W1odWNRYm9RpU4XBAXDvpA==,type:str]
sops:
lastmodified: "2026-01-27T15:12:24Z"
mac: ENC[AES256_GCM,data:AupZMMI0ycLlxF3/s2fLy97AC75/QF7itpaldF+I6Cuoj6FdmBd+2HwiDuz+505ZAm0/pP7Ez7p+zA7STyxY0vzGBu2XoOhKOcj0seJHrHZh60PXlV2BgQarBxVTtSg3BWFLrKYNRRHevHezfRKxFichlQZzj5Pc6TmheNs2c7U=,iv:TXYL4TE8GlAeuTjaw9GfdP+mmXtWpz++sHp0InHk04c=,tag:0I+c3wRyLh2vL+9N7K5i+w==,type:str]
pgp:
- created_at: "2026-01-27T15:12:24Z"
enc: |-
-----BEGIN PGP MESSAGE-----

hF4Dy77zzNMwU0sSAQdA/biMrPzXXQ6FZhsAqOpLTXUzegYmekUNov4ZxfhQyWsw
GLEYcoYdGLjZo/BSUP3t6+8XJ/LY6ytRvMvsxWWJKGBspxIyE7JwTCpIdOWA4p0v
0lwBlyu0o8Jc31ct4J1V+mPowF8L1znKEgqVBugA+l3N5JRizwecTdcb8k0OXHqf
+hXfcCYVK5FYJbdtGsGEEZmS6vGjdAViNiTyuS4NS+Lh4sEFXA0Z4CT7YILArA==
=5nCL
-----END PGP MESSAGE-----
fp: 8DEE2D0E1357B78C782691234A2D3B6C7E35AEF7
unencrypted_suffix: _unencrypted
version: 3.11.0
24 changes: 24 additions & 0 deletions kustomize/overlays/tests/exploit-iq-client-build-ips-enc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: ENC[AES256_GCM,data:V0g=,iv:aku+6VNcpHX/VwyWNuHMU9p1UJn9QgI9az5pl57Up0c=,tag:9cHqcamNq/n459qQRu6bKg==,type:str]
data:
.dockerconfigjson: ENC[AES256_GCM,data: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,iv:GiAFMGtzev6bnTtbKrhaUmJipZfYEriVDR0hIIcbuvk=,tag:p87FISG6OFI5n2suKECcKg==,type:str]
kind: ENC[AES256_GCM,data:oDXj1wmI,iv:zRQA0DPLBhe7skXIqE4vLQKlQgzsOW7PhmSQBTUhVcw=,tag:NeNhMXL3nrFDXVGiISQqvw==,type:str]
metadata:
name: ENC[AES256_GCM,data:YWKVdWVd7Vkby+mGaoqCCdFbZnk=,iv:xNy7/XNWt0Ng7A45WEZ+K8RQD6inqy9TEhVFqnWzxm0=,tag:X+ar+MFIhG4Nsz5gwopLJg==,type:str]
type: ENC[AES256_GCM,data:tC3kqUKpNt1xPF8COd35itVzvDwEXxmOvnc5iYOT,iv:4KHXCxzXmH2LSX3/WmvWjeol2kG9FtcB9K1vczpoS2k=,tag:EkcbbOGnUM5ICiwV9fyYog==,type:str]
sops:
lastmodified: "2026-01-27T14:58:25Z"
mac: ENC[AES256_GCM,data:4QX9acqwVT0yIblv0/On8BZVK3d47GcLccXhWWyrdRYW+4BgR8zc1v+k1YRxJEBlojlXNqvaFs9tEEdNWQ0QHBUsR8jMQ0T2t5EqHb9LPE4WOYuBVcTyeqDmyc01EKHDWdutYxo15kotCMG1FO5OgZ11Rcwdv3f1QVdgskN4Pks=,iv:kiq2siF75QwGOK84k013AD8ex5N/kPMc6FrUOp531v0=,tag:Qq2Y1COIOw46WyU/qUH+ZQ==,type:str]
pgp:
- created_at: "2026-01-27T14:58:25Z"
enc: |-
-----BEGIN PGP MESSAGE-----

hF4Dy77zzNMwU0sSAQdAeDQZY4S70FaOHXTn3u7lIZfKvrpRyBtH5osQEepI+E4w
NnlXnnxgtOHBU8nHJZK2vmNge1hVUaGBcZ+mvsnanMEs0zpFkn2LD1hoQhVR+kYo
0l4BIJTzMKoU0+NlCheUC8dD4lPhgVszP+Lis2ftddN2+q3rAwkcpBZC3ADkw4lp
GFuWjTCeNbfrWV5VGPj0rUfgXrqBS49df/aBBlkwCuEI+iwKFaw6UE21TrOT7p6L
=MreB
-----END PGP MESSAGE-----
fp: 8DEE2D0E1357B78C782691234A2D3B6C7E35AEF7
unencrypted_suffix: _unencrypted
version: 3.11.0
15 changes: 15 additions & 0 deletions kustomize/overlays/tests/exploit-iq-ips.secret
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:7Mhg0suh1pr4gW2ZSVDfDVBxR9M+WeOS/ndzCa6HynWbnbVi6o/bXSBrUwukb9NLEPyXG+i0Ja265AmV2Ix//+0YiHxRMTNWuAWeik9C1FhPyMefg/QJ7/TqVA19011U1oaqZwttcfxtiC69lKbIG6vZnxuLtWhjoWfi1SJrqPZ+EsKSD/st2DoWkhvlGd+ea8RyboXt2knL2jy7smo1wRWSUl98SqDr6TLqNg==,iv:oup5Ep55EXokJe+jRlOBXIxGoP88ZqV6aHzQtDrAGok=,tag:UuwWcFrQ8OJf5weq0HNBrg==,type:str]",
"sops": {
"lastmodified": "2026-01-25T12:11:15Z",
"mac": "ENC[AES256_GCM,data:o+/YRK8wHs6hlEJqkwDtzV/3plYxOTRs7QGfqLGv0TaGZMIYFnbav1M4AFDYY7pMxEnRCyRJWr6G6L3mN8Uwdcr9FyMls1yQAXnu8a6iP7xLSvShvk4sXmdRKCV+ZoI6uWOGpT5um2ovpqce2GENStvk7PhFhS0R+Dc2IqBYbyA=,iv:rWe1RZ8QEIeOTrIVYTroLrqm9QaugtTVw41dtxJRk5Y=,tag:CRh9MgwYzbLV+fqkIjpcxA==,type:str]",
"pgp": [
{
"created_at": "2026-01-25T12:11:15Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhF4Dy77zzNMwU0sSAQdAenSUkHYnXpk59IsDKXVzwzXcmJYgwOC/mjNFPxrPUQkw\nIroNi7SaoYcdQ5bNd/IygS+LSJbqxWpMvPLgxw+Z/BUS0lWppfzAYgMeHGjH5Y+u\n0lwBGxusz5C9WM+oOHNOhrg8DZZU3iLfDgWpICqJ6OtRlcSlJlr2gXPFZngunkxz\nX5fFnLDgs2j6OV5CQEAkjC3j73t9RSE61ILuRLqZGMFjCm/xtL7KieKhstFxqw==\n=mhUv\n-----END PGP MESSAGE-----",
"fp": "8DEE2D0E1357B78C782691234A2D3B6C7E35AEF7"
}
],
"version": "3.11.0"
}
}
Loading