Skip to content

Commit f048aa8

Browse files
committed
Merge branch 'dev' into remove-credential-manager
2 parents e70b19d + 817a36c commit f048aa8

36 files changed

Lines changed: 33079 additions & 602 deletions
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
title: "Xygeni"
3+
toc_hide: true
4+
---
5+
### About Xygeni
6+
[Xygeni](https://xygeni.io) is a Software Supply Chain Security platform whose
7+
scanners produce JSON reports for code vulnerabilities (SAST), open-source
8+
dependency vulnerabilities (SCA), hard-coded secrets, IaC flaws, web-application
9+
vulnerabilities (DAST), CI/CD and SCM misconfigurations, and malicious or
10+
suspect components.
11+
12+
This parser handles three Xygeni scan kinds in phase 1: **SAST**, **SCA**, and
13+
**Secrets**. All three share a common `metadata` envelope; the parser
14+
dispatches on `metadata.scanType`.
15+
16+
### Scan Types
17+
| Scan type | `metadata.scanType` | Xygeni CLI command (typical) |
18+
| ------------------------ | ------------------- | ---------------------------- |
19+
| `Xygeni SAST Scan` | `sast` | `xygeni scan --scan-type=sast --format=json` |
20+
| `Xygeni SCA Scan` | `deps` | `xygeni scan --scan-type=deps --format=json` |
21+
| `Xygeni Secrets Scan` | `secrets` | `xygeni scan --scan-type=secrets --format=json` |
22+
23+
See the Xygeni documentation at <https://docs.xygeni.io> for installation and
24+
the full set of CLI options.
25+
26+
### Acceptable JSON Format
27+
All three scan types share the same envelope:
28+
29+
~~~
30+
{
31+
"metadata": {
32+
"uuid": "...",
33+
"timestamp": "2026-04-26T07:08:29Z",
34+
"projectName": "...",
35+
"scanType": "sast" | "deps" | "secrets",
36+
"format": "<scanType>-xygeni",
37+
"reportProperties": {
38+
"tool.name": "Xygeni",
39+
"tool.version": "..."
40+
}
41+
},
42+
...
43+
}
44+
~~~
45+
46+
The kind-specific payload then follows:
47+
48+
- **SAST**`vulnerabilities[]` — each entry carries `detector` (the rule id),
49+
`severity`, `location.{filepath, beginLine, endLine, code}`, `cwe` /
50+
`cwes[]`, `tags[]`, `explanation`, `uniqueHash`, `issueId`, and an optional
51+
`codeFlows[]` block describing source / sink frames and the data path.
52+
- **SCA**`dependencies[]` — each dependency has `name`, `version`,
53+
`ecosystem`, and a nested `vulnerabilities[]` of CVE/GHSA advisories with
54+
`cve`, `cwes`, `fixedVersion`, `aliases`, `overallCvssScore`, `references`,
55+
`description`, `uniqueHash`, `issueId`.
56+
- **Secrets**`secrets[]` — each entry has `type` (e.g.
57+
`aws_access_key`), `detector`, `severity`, `location` (same shape as SAST),
58+
`description`, `tags`, `uniqueHash`, `issueId`. The `secret` value and
59+
`location.code` are already redacted by the Xygeni CLI before serialisation.
60+
61+
### Sample Scan Data
62+
Sample Xygeni JSON reports can be found
63+
[here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/xygeni).
64+
65+
### Deduplication
66+
67+
Every finding carries `unique_id_from_tool` (set from Xygeni's vendor-stable
68+
`uniqueHash`) and `vuln_id_from_tool` (set from `issueId`). The deduplication
69+
algorithm is configured per scan type:
70+
71+
| Scan type | Algorithm | Hash-code fields (fallback) |
72+
| -------------------- | ---------------------------------- | -------------------------------------------------------------- |
73+
| Xygeni SAST Scan | `unique_id_from_tool` | n/a |
74+
| Xygeni SCA Scan | `unique_id_from_tool_or_hash_code` | `vulnerability_ids`, `component_name`, `component_version` |
75+
| Xygeni Secrets Scan | `unique_id_from_tool` | n/a |
76+
77+
For SCA the hash-code fallback enables cross-tool deduplication: the same
78+
CVE on the same package@version reported by Xygeni and another SCA scanner
79+
(Snyk, Trivy, etc.) collapse into a single Finding.

dojo/api_v2/mixins.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from rest_framework.decorators import action
99

1010
from dojo.api_v2 import serializers
11-
from dojo.models import Answer, Question
1211

1312

1413
class DeletePreviewModelMixin:
@@ -46,13 +45,3 @@ def flatten(elem):
4645

4746
serializer = serializers.DeletePreviewSerializer(page, many=True)
4847
return self.get_paginated_response(serializer.data)
49-
50-
51-
class QuestionSubClassFieldsMixin:
52-
def get_queryset(self):
53-
return Question.objects.select_subclasses()
54-
55-
56-
class AnswerSubClassFieldsMixin:
57-
def get_queryset(self):
58-
return Answer.objects.select_subclasses()

dojo/api_v2/serializers.py

Lines changed: 0 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,9 @@
4848
SEVERITY_CHOICES,
4949
STATS_FIELDS,
5050
Announcement,
51-
Answer,
52-
Answered_Survey,
5351
App_Analysis,
5452
BurpRawRequestResponse,
5553
Check_List,
56-
ChoiceAnswer,
57-
ChoiceQuestion,
5854
Development_Environment,
5955
Dojo_Group,
6056
Dojo_Group_Member,
@@ -65,12 +61,10 @@
6561
Endpoint_Status,
6662
Engagement,
6763
Engagement_Presets,
68-
Engagement_Survey,
6964
FileUpload,
7065
Finding,
7166
Finding_Group,
7267
Finding_Template,
73-
General_Survey,
7468
Global_Role,
7569
Language_Type,
7670
Languages,
@@ -85,7 +79,6 @@
8579
Product_Type,
8680
Product_Type_Group,
8781
Product_Type_Member,
88-
Question,
8982
Regulation,
9083
Risk_Acceptance,
9184
Role,
@@ -98,8 +91,6 @@
9891
Test_Import,
9992
Test_Import_Finding_Action,
10093
Test_Type,
101-
TextAnswer,
102-
TextQuestion,
10394
Tool_Configuration,
10495
Tool_Product_Settings,
10596
Tool_Type,
@@ -3106,111 +3097,6 @@ class Meta:
31063097
exclude = ("content_type",)
31073098

31083099

3109-
class QuestionnaireQuestionSerializer(serializers.ModelSerializer):
3110-
def to_representation(self, instance):
3111-
if isinstance(instance, TextQuestion):
3112-
return TextQuestionSerializer(instance=instance).data
3113-
if isinstance(instance, ChoiceQuestion):
3114-
return ChoiceQuestionSerializer(instance=instance).data
3115-
return QuestionSerializer(instance=instance).data
3116-
3117-
class Meta:
3118-
model = Question
3119-
exclude = ("polymorphic_ctype",)
3120-
3121-
3122-
class QuestionSerializer(serializers.ModelSerializer):
3123-
class Meta:
3124-
model = Question
3125-
exclude = ("polymorphic_ctype",)
3126-
3127-
3128-
class TextQuestionSerializer(serializers.ModelSerializer):
3129-
class Meta:
3130-
model = TextQuestion
3131-
exclude = ("polymorphic_ctype",)
3132-
3133-
3134-
class ChoiceQuestionSerializer(serializers.ModelSerializer):
3135-
choices = serializers.StringRelatedField(many=True)
3136-
3137-
class Meta:
3138-
model = ChoiceQuestion
3139-
exclude = ("polymorphic_ctype",)
3140-
3141-
3142-
class QuestionnaireAnsweredSurveySerializer(serializers.ModelSerializer):
3143-
class Meta:
3144-
model = Answered_Survey
3145-
fields = "__all__"
3146-
3147-
3148-
class QuestionnaireAnswerSerializer(serializers.ModelSerializer):
3149-
def to_representation(self, instance):
3150-
if isinstance(instance, TextAnswer):
3151-
return TextAnswerSerializer(instance=instance).data
3152-
if isinstance(instance, ChoiceAnswer):
3153-
return ChoiceAnswerSerializer(instance=instance).data
3154-
return AnswerSerializer(instance=instance).data
3155-
3156-
class Meta:
3157-
model = Answer
3158-
exclude = ("polymorphic_ctype",)
3159-
3160-
3161-
class AnswerSerializer(serializers.ModelSerializer):
3162-
question = serializers.StringRelatedField()
3163-
answered_survey = QuestionnaireAnsweredSurveySerializer()
3164-
3165-
class Meta:
3166-
model = Answer
3167-
exclude = ("polymorphic_ctype",)
3168-
3169-
3170-
class TextAnswerSerializer(serializers.ModelSerializer):
3171-
question = serializers.StringRelatedField()
3172-
answered_survey = QuestionnaireAnsweredSurveySerializer()
3173-
3174-
class Meta:
3175-
model = TextAnswer
3176-
exclude = ("polymorphic_ctype",)
3177-
3178-
3179-
class ChoiceAnswerSerializer(serializers.ModelSerializer):
3180-
answer = serializers.StringRelatedField(many=True)
3181-
question = serializers.StringRelatedField()
3182-
answered_survey = QuestionnaireAnsweredSurveySerializer()
3183-
3184-
class Meta:
3185-
model = ChoiceAnswer
3186-
exclude = ("polymorphic_ctype",)
3187-
3188-
3189-
class QuestionnaireEngagementSurveySerializer(serializers.ModelSerializer):
3190-
questions = serializers.SerializerMethodField()
3191-
3192-
@extend_schema_field(serializers.ListField(child=serializers.CharField()))
3193-
def get_questions(self, obj):
3194-
questions = obj.questions.all()
3195-
formated_questions = []
3196-
for question in questions:
3197-
formated_question = f"Order #{question.order} - {question.text}{' (Optional)' if question.optional else ''}"
3198-
formated_questions.append(formated_question)
3199-
return formated_questions
3200-
3201-
class Meta:
3202-
model = Engagement_Survey
3203-
fields = "__all__"
3204-
3205-
3206-
class QuestionnaireGeneralSurveySerializer(serializers.ModelSerializer):
3207-
survey = QuestionnaireEngagementSurveySerializer()
3208-
3209-
class Meta:
3210-
model = General_Survey
3211-
fields = "__all__"
3212-
3213-
32143100
class AnnouncementSerializer(serializers.ModelSerializer):
32153101

32163102
class Meta:

0 commit comments

Comments
 (0)