Skip to content

Commit ff03821

Browse files
committed
feat(spec): add providers
This adds a more opinionated structure for providers Signed-off-by: xibz <bjp@apple.com> Signed-off-by: xibz <impactbchang@gmail.com> Signed-off-by: xibz <bjp@apple.com>
1 parent b2d364c commit ff03821

6 files changed

Lines changed: 171 additions & 21 deletions

File tree

PROVIDERS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# CDEvents Provider Registry
2+
3+
The canonical registry of known `provider` values is [`schemas/registry/providers.json`](schemas/registry/providers.json). SDKs MUST use this list as the default for provider validation. See the [Provider Validation](links.md#provider-validation) section in `links.md` for the full SDK validation requirements.
4+
5+
To register a provider, open a pull request adding an entry to the enum in [`schemas/registry/providers.json`](schemas/registry/providers.json). Provider identifiers MUST be lowercase, start with a letter, and contain only alphanumeric characters and hyphens. Once merged, the value is considered stable and MUST NOT be renamed.

conformance/formats/domainid.json

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
{
2+
"description": "Test vectors for domainId URN serialization. Each valid case specifies the logical segments and the expected serialized string. SDKs MUST produce the expected string from the given segments and MUST parse the expected string back to the same segments (round-trip).",
3+
"valid": [
4+
{
5+
"description": "GitHub PR, no provider-id",
6+
"segments": {
7+
"provider": "github",
8+
"providerId": "",
9+
"namespace": "xibz",
10+
"groups": "cdevents-spec",
11+
"type": "pr",
12+
"resourceId": "42"
13+
},
14+
"expected": "cdevents:v0:github::xibz:cdevents-spec:pr:42"
15+
},
16+
{
17+
"description": "GitHub PR with provider-id distinguishing two internal GitHub Enterprise deployments",
18+
"segments": {
19+
"provider": "github",
20+
"providerId": "org-a-github",
21+
"namespace": "xibz",
22+
"groups": "cdevents-spec",
23+
"type": "pr",
24+
"resourceId": "42"
25+
},
26+
"expected": "cdevents:v0:github:org-a-github:xibz:cdevents-spec:pr:42"
27+
},
28+
{
29+
"description": "Jira ticket, no provider-id",
30+
"segments": {
31+
"provider": "jira",
32+
"providerId": "",
33+
"namespace": "xibz",
34+
"groups": "cdevents-project",
35+
"type": "issue",
36+
"resourceId": "PROJ-123"
37+
},
38+
"expected": "cdevents:v0:jira::xibz:cdevents-project:issue:PROJ-123"
39+
},
40+
{
41+
"description": "GitLab MR with nested groups",
42+
"segments": {
43+
"provider": "gitlab",
44+
"providerId": "",
45+
"namespace": "my-company",
46+
"groups": "platform/backend",
47+
"type": "mr",
48+
"resourceId": "99"
49+
},
50+
"expected": "cdevents:v0:gitlab::my-company:platform/backend:mr:99"
51+
},
52+
{
53+
"description": "Datadog alert, no provider-id",
54+
"segments": {
55+
"provider": "datadog",
56+
"providerId": "",
57+
"namespace": "prod",
58+
"groups": "api-monitors",
59+
"type": "alert",
60+
"resourceId": "98765"
61+
},
62+
"expected": "cdevents:v0:datadog::prod:api-monitors:alert:98765"
63+
},
64+
{
65+
"description": "Docker artifact using PURL as resource id — provider, provider-id, namespace and groups all empty because registry is unknown",
66+
"segments": {
67+
"provider": "",
68+
"providerId": "",
69+
"namespace": "",
70+
"groups": "",
71+
"type": "artifact",
72+
"resourceId": "pkg%3Adocker%2Fmyapp%401.0.0"
73+
},
74+
"expected": "cdevents:v0:::::artifact:pkg%3Adocker%2Fmyapp%401.0.0"
75+
},
76+
{
77+
"description": "All optional segments empty — only type and resource id present; structurally valid",
78+
"segments": {
79+
"provider": "",
80+
"providerId": "",
81+
"namespace": "",
82+
"groups": "",
83+
"type": "pr",
84+
"resourceId": "42"
85+
},
86+
"expected": "cdevents:v0:::::pr:42"
87+
}
88+
],
89+
"invalid": [
90+
{
91+
"description": "Missing provider-id segment (only 6 colons)",
92+
"input": "cdevents:v0:github:xibz:cdevents-spec:pr:42",
93+
"reason": "Segment count mismatch — provider-id segment omitted rather than left empty"
94+
},
95+
{
96+
"description": "Empty type",
97+
"input": "cdevents:v0:github::xibz:cdevents-spec::42",
98+
"reason": "type is required and must not be empty"
99+
},
100+
{
101+
"description": "Empty resource id",
102+
"input": "cdevents:v0:github::xibz:cdevents-spec:pr:",
103+
"reason": "resource id is required and must not be empty"
104+
},
105+
{
106+
"description": "Leading slash in groups",
107+
"input": "cdevents:v0:github::xibz:/cdevents-spec:pr:42",
108+
"reason": "Leading '/' in groups is invalid"
109+
},
110+
{
111+
"description": "Trailing slash in groups",
112+
"input": "cdevents:v0:github::xibz:cdevents-spec/:pr:42",
113+
"reason": "Trailing '/' in groups is invalid"
114+
},
115+
{
116+
"description": "Wrong version",
117+
"input": "cdevents:v1:github::xibz:cdevents-spec:pr:42",
118+
"reason": "Only v0 is currently defined"
119+
},
120+
{
121+
"description": "Wrong scheme prefix",
122+
"input": "CDEvents:v0:github::xibz:cdevents-spec:pr:42",
123+
"reason": "Scheme must be lowercase 'cdevents'"
124+
}
125+
]
126+
}

links.md

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -610,10 +610,6 @@ causality in `customData`, where it is unstructured and non-queryable.
610610
across system boundaries, regardless of whether the referenced system emits
611611
CDEvents.
612612

613-
This is a transitional mechanism: as more systems adopt CDEvents, `domainId`
614-
links naturally migrate to `contextId` links. It is a bridge, not a
615-
permanent replacement.
616-
617613
### Event-to-Event vs Event-to-Resource Linking
618614

619615
`contextId` and `domainId` represent two fundamentally different linking models.
@@ -657,7 +653,6 @@ domainId — many-to-many (N events, M resources)
657653
| domainId: | | domainId: | | domainId: |
658654
| cdevents:v0: | | cdevents:v0: | | cdevents:v0: |
659655
| github::xibz:... | | github::xibz:... | | github::xibz:... |
660-
| :pr:42 | | :pr:42 | | :pr:42 |
661656
+------------------+ +-------------------+ +------------------+
662657
663658
@@ -693,15 +688,19 @@ cdevents:v0:<provider>:<provider-id>:<namespace>:<groups>:<type>:<resource id>
693688

694689
All segments MUST be present. If a segment has no value, it MUST be left empty rather than omitted (e.g. `cdevents:v0:github::xibz:...`). Omitting a segment shifts all following segments and introduces ambiguity.
695690

696-
| Segment | Description |
697-
|---------------|----------------------------------------------------------------------------------------------------------------|
698-
| `version` | The version of the `domainId` URN format (currently `v0`). This allows the format to evolve without breaking existing consumers. |
699-
| `provider` | A governed identifier for the tool. Must match a known provider defined in the CDEvents provider list within this spec (e.g. `github`, `jira`, `datadog`). Free-form values are not permitted. |
700-
| `provider-id` | A company or org-defined identifier for the specific deployment of the provider (e.g. distinguishing one internal GitHub Enterprise from another). CDEvents does not govern this value — producers and consumers within an organization must agree on it. |
701-
| `namespace` | The top-level organizational unit within the provider's data model (e.g., a GitHub org, a Jira workspace). Producer-defined; not governed by CDEvents. |
702-
| `groups` | One or more organizational subdivisions within the namespace, separated by `/` to express nesting as defined by the provider's data model. For example, a GitHub repository is a single group (`my-repo`); a GitLab project nested under subgroups would be `group/subgroup/project`. Leading and trailing `/` are invalid. Producer-defined; not governed by CDEvents. |
703-
| `type` | A governed resource type. Must be one of the values defined in [Common Resource Types](#common-resource-types) |
704-
| `resource id` | The publicly exposed identifier that end users see for this resource (e.g. a PR number, commit SHA, or ticket number). Must not be an internal or opaque system-generated ID. |
691+
Only `type` and `resource id` are required to be non-empty. All other segments are contextual — they narrow the identity of the resource but MAY be left empty when the information is not known or not applicable (e.g. an artifact whose provider registry is unknown).
692+
693+
Segment values MUST reflect the exact canonical form as the value appears in the provider's system, before encoding is applied. When URL-encoding is required, percent-encoded hex digits MUST be uppercase (e.g. `%2F` not `%2f`).
694+
695+
| Segment | Required | Description |
696+
|---------------|----------|----------------------------------------------------------------------------------------------------------------|
697+
| `version` | yes | The version of the `domainId` URN format (currently `v0`). This allows the format to evolve without breaking existing consumers. |
698+
| `provider` | no | A governed identifier for the tool or system type that owns the resource. When present, MUST match a known provider defined in [PROVIDERS.md](PROVIDERS.md). Free-form values are not permitted — without a governed list, the same tool would be referenced as `gh`, `github`, `GitHub`, etc., making cross-system queries unreliable. |
699+
| `provider-id` | no | Identifies who owns and where a specific instance of the provider is running. This is entirely company or org-defined — CDEvents does not govern, assign, or interpret this value. It exists solely to distinguish between two instances of the same tool owned or operated by different teams or organizations (e.g. org A's internal GitHub Enterprise vs org B's). Producers and consumers within an organization MUST agree on the value out of band. MUST be URL-encoded when present. |
700+
| `namespace` | no | The top-level organizational unit within the provider's data model (e.g., a GitHub org, a Jira workspace). Producer-defined; not governed by CDEvents. MUST be URL-encoded when present. |
701+
| `groups` | no | One or more organizational subdivisions within the namespace, separated by `/` to express nesting as defined by the provider's data model. For example, a GitHub repository is a single group (`my-repo`); a GitLab project nested under subgroups would be `group/subgroup/project`. The `/` separator is structural and MUST NOT be encoded. Individual group segment values MUST be URL-encoded. Leading and trailing `/` are invalid. Producer-defined; not governed by CDEvents. |
702+
| `type` | yes | A governed resource type. MUST be one of the values defined in [Common Resource Types](#common-resource-types) |
703+
| `resource id` | yes | The publicly exposed identifier that end users see for this resource (e.g. a PR number, commit SHA, ticket number, or PURL). MUST be URL-encoded. MUST NOT be an internal or opaque system-generated ID. |
705704

706705
Examples:
707706

@@ -712,6 +711,14 @@ Examples:
712711
- Datadog alert: `cdevents:v0:datadog::prod:api-monitors:alert:98765`
713712
- GitLab MR (nested groups): `cdevents:v0:gitlab::my-company:platform/backend:mr:99`
714713

714+
### Provider Validation
715+
716+
The `provider` segment MUST match a known provider. CDEvents ships a default governed list of commonly used providers in [PROVIDERS.md](PROVIDERS.md), which serves as the baseline for validation.
717+
718+
SDKs MUST support extending the provider list at initialization time, allowing organizations to register additional providers beyond the CDEvents default. Validation MUST check against the union of the CDEvents default list and any organization-supplied providers.
719+
720+
When a `provider` value is not found in either list, the SDK SHOULD emit a warning. Whether to reject or allow the value SHOULD be configurable by the caller.
721+
715722
### Common Resource Types
716723

717724
The `type` segment is a governed field. Producers MUST use one of the following
@@ -727,7 +734,7 @@ without handling variations like `pull_request`, `PR`, or `pullrequest`.
727734
| `tag` | A source code tag or release | `v1.2.3` |
728735
| `definition` | A named, reusable pipeline or workflow template | `my-pipeline` |
729736
| `execution` | A single run of a build, pipeline, workflow, or deployment | `789` (run number) |
730-
| `artifact` | A build artifact (binary, container image, package, etc.) | `myapp:1.0.0` |
737+
| `artifact` | A build artifact (binary, container image, package, etc.). The resource id SHOULD be a [PURL](https://github.com/package-url/purl-spec), URL-encoded. | `pkg%3Adocker%2Fmyapp%401.0.0` |
731738
| `environment` | A target deployment environment | `production`, `staging` |
732739
| `alert` | A monitoring or observability alert | `98765` (alert ID) |
733740

schemas/links/domainid.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://cdevents.dev/0.6.0-draft/schema/links/domainid",
4+
"description": "A canonical CDEvents domain ID URN that identifies a resource in an external system that does not emit CDEvents. The provider-id, namespace, individual group segment values within groups, and resource id MUST be URL-encoded. The '/' separator between group segments is structural and MUST NOT be encoded. The provider segment MUST be validated separately against ../registry/providers.json.",
5+
"type": "string",
6+
"format": "uri-reference",
7+
"pattern": "^cdevents:v0:[^:]*:[^:]*:[^:]*:([^:/]([^:]*[^:/])?)?:[^:]+:.+$",
8+
"examples": [
9+
"cdevents:v0:github::xibz:cdevents-spec:pr:42",
10+
"cdevents:v0:github:org-a-github:xibz:cdevents-spec:pr:42",
11+
"cdevents:v0:jira::xibz:cdevents-project:issue:PROJ-123",
12+
"cdevents:v0:datadog::prod:api-monitors:alert:98765",
13+
"cdevents:v0:gitlab::my-company:platform/backend:mr:99"
14+
]
15+
}

schemas/links/embeddedlinkrelation.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
"minLength": 1
2222
},
2323
"domainId": {
24-
"type": "string",
25-
"format": "uri-reference"
24+
"$ref": "domainid.json"
2625
}
2726
},
2827
"anyOf": [

schemas/links/linkrelation.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030
"minLength": 1
3131
},
3232
"domainId": {
33-
"type": "string",
34-
"format": "uri-reference"
33+
"$ref": "domainid.json"
3534
}
3635
},
3736
"anyOf": [
@@ -48,8 +47,7 @@
4847
"minLength": 1
4948
},
5049
"domainId": {
51-
"type": "string",
52-
"format": "uri-reference"
50+
"$ref": "domainid.json"
5351
}
5452
},
5553
"anyOf": [

0 commit comments

Comments
 (0)