Skip to content

feat: This is a simplification of the Consumer API Spec #180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

madpah
Copy link
Collaborator

@madpah madpah commented May 30, 2025

This is draft PR that follows the Slack discussions here and here - supported by the attached Zoom Whiteboard (also here) where @nscuro and myself considered, from the Consumer perspective a simplification whilst also consider (as discussed during OWASP Hackathon) the necessary support for Product Versioning.

Revised API Flow (Main Flow)

sequenceDiagram
    actor Client
    Client->>TEA Service: POST /product/search with TEI
    TEA Service-->>Client: TEA Product returned
    Note over TEA Service: This includes a list of TEA Collection identifiers

    loop For every TEA Collection identifier
    Client->>TEA Service: GET /collection/{id}/latest
    TEA Service-->>Client: TEA Collection returned
    Note over TEA Service: This includes all TEA Artifacts in the TEA Collection
    end
Loading

References / Workings

Revised simplified data model suggestion (data model, not API Spec):
Consumer API Spec Review - OWASP Hackathon_Page 3- 1748631550990

Worked examples:
Consumer API Spec Hackathon Review_Page 2- 1748631519807

FYI @stevespringett

@madpah madpah added OpenAPI spec hackathon Raised during OWASP Hackathon labels May 30, 2025
@madpah madpah self-assigned this May 30, 2025
@taleodor
Copy link
Contributor

There are great ideas here, but I feel like the logic breaks when we try to define the concepts of "unversioned product" and "latest versions of components".

Observe that:

  • A set of components may change between product releases (say, we dropped, added or replaced an upstream component)
  • "Latest" release is frequently not clearly defined, i.e. may a "pre-release" be considered latest?
  • Let's assume we defined "Latest" - this would imply that we still need binding for all Component Releases to be able to select the "Latest" among them. That means that the "Component" object entity is still present, just hidden in the model. Of course, we may let implementations work this out, but if this is already clear that the "Component" entity must exist in any case, why not have that added explicitly to the spec? Similar reasoning can be applied to "Product" -> "Product Releases" relationship.

If we respect these limitation, this will actually become very close to the existing spec with certain updates. Particularly, what I really like about this PR is "/product/search" POST call. However, I don't think it's a replacement for /product/{uuid} due to limitations mentioned above.

Copy link
Contributor

@ppkarwasz ppkarwasz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @madpah,

Thanks for sharing this! I think this PR has the potential to simplify TEA nicely. Even if it’s still an early draft, I wanted to highlight a few concerns and questions I have about the proposed changes.

Comment on lines +20 to +21
/product/search:
post:
Copy link
Contributor

@ppkarwasz ppkarwasz May 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this change addresses the concerns in #159 about percent-encoding the TEI in the URL path.

Switching to POST simplifies clients but prevents deploying a TEA service on static web servers like GitHub Pages, which can only serve GET requests. I'd like to see TEA work across the full spectrum—from static sites to dynamic services. Using only GET with path parameters for the most important endpoints could help preserve that flexibility.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppkarwasz The working group should make a decision as to whether such static deployments must be supported. IMO, it would heavily limit what the API can offer and express.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some parts of the API certainly could require a dynamically generated response. For example /products require such a response, unless you totally ignore all query parameters.

However, I believe that dynamic endpoints should be used sparingly, when there is no alternative. In this case the alternative is clear: the TEI can be properly encoded and passed as path parameter.

examples:
- urn:tei:ean:philips-hue.com:8719514329928
- urn:tei:hash:cyclonedx.org:SHA256:fd44efd601f651c8865acf0dfeacb0df19a2b50ec69ead0262096fd2f67197b9
- urn:tei:purl:cyclonedx.org:pkg:pypi/[email protected]?extension=whl&qualifier=py3-none-any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- urn:tei:purl:cyclonedx.org:pkg:pypi/[email protected]?extension=whl&qualifier=py3-none-any
- urn:tei:purl:cyclonedx.org:pkg:pypi/[email protected]%3Fextension=whl&qualifier=py3-none-any

RFC 8141 does not allow ? to appear unencoded in an NSS.

Comment on lines +37 to +41
description: TEA Product found and returned
content:
application/json:
schema:
$ref: "#/components/schemas/product"
"$ref": "#/components/schemas/product"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which version of the product object should be returned by this query?

Should it be the latest one? If so, can we retrieve other version of the TEA Product?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refer to the screenshots @madpah added to the PR description. Searching by a TEI without version qualifier returns the latest version, whereas searching with version qualifier yields that specific version:

image

Comment on lines 455 to +468
- uuid: 09e8c73b-ac45-4475-acac-33e6a7314e6d
name: Apache Log4j 2
version: 2.12.0
createdAt: 2017-07-21T17:32:28.003Z
preRelease: false
identifiers:
- idType: CPE
idValue: cpe:2.3:a:apache:log4j
idValue: cpe:2.3:a:apache:log4j:2.12.0
- idType: PURL
idValue: pkg:maven/org.apache.logging.log4j/log4j-api
idValue: pkg:maven/org.apache.logging.log4j/log4j-api@2.12.0
- idType: PURL
idValue: pkg:maven/org.apache.logging.log4j/log4j-core
idValue: pkg:maven/org.apache.logging.log4j/log4j-core@2.12.0
- idType: PURL
idValue: pkg:maven/org.apache.logging.log4j/log4j-layout-template-json
idValue: pkg:maven/org.apache.logging.log4j/log4j-layout-template-json@2.12.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: in previous conversations it was pointed out that these PURLs do not belong to the TEA Product, but the TEA Components. Could your remove them?

These PURLs do not point to the entire product, but only part of it.

Comment on lines -313 to -317
identifiers:
type: array
description: List of identifiers for the component
items:
"$ref": "#/components/schemas/identifier"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identifiers specific to a single TEA Component could be stored in the component object.

3. Philips Hue Bulb

It is also permissible for a TEA Component to also be a TEA Product by also creating a
separate TEA Product that refers to same TEA Component.
properties:
uuid:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: you didn't rename component.uuid to component.id.

Comment on lines +49 to +51
/component/{id}:
get:
description: Get a TEA Component
description: Get a TEA Component by it's Identifier
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The semantics of the id in /component/{id} are unclear:

  • If multiple component versions share the same id, which version does this endpoint return?
  • If each component version has a unique id, how can clients retrieve all versions of a given component?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If multiple component versions share the same id, which version does this endpoint return?

With the idea being to collapse the logical models of Component and Component Release, id would always refer to a specific component version.

If each component version has a unique id, how can clients retrieve all versions of a given component?

What is the use case for listing all versions of a component? tea-usecases.md doesn't seem to have any.

If you're referring to use case D1, that use case will need a separate discovery mechanism anyway, and would work just as well if all component versions are distinct records.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an issue about discovering new versions of a component (#36).

@nscuro
Copy link
Member

nscuro commented Jun 4, 2025

@taleodor "Latest" release is frequently not clearly defined, i.e. may a "pre-release" be considered latest?

I would suggest to not try to infer "latest" somehow - this is bound to fail due to the various ambiguities in versioning and release patterns. Instead, let's let publishers explicitly define what version is "latest". This mirrors what you can do in GitHub Releases, and FWIW, it's a mechanism that DT has adopted as well.

@taleodor Let's assume we defined "Latest" - this would imply that we still need binding for all Component Releases to be able to select the "Latest" among them. [...] Similar reasoning can be applied to "Product" -> "Product Releases" relationship.

Possibly. Excuse my ignorance, and this is likely because I joined the effort so late, but where does the need to determine the "latest" component release stem from?

Are we trying to mix transparency artifact exchange with generalized component (version) discovery? Doesn't it suffice for TEA to track component versions as-is?

I get the need for this on the product level, but components?

@taleodor
Copy link
Contributor

taleodor commented Jun 4, 2025

@nscuro

I would suggest to not try to infer "latest" somehow - this is bound to fail due to the various ambiguities in versioning and release patterns. Instead, let's let publishers explicitly define what version is "latest". This mirrors what you can do in GitHub Releases, and FWIW, it's a mechanism that DT has adopted as well.

GitHub Releases has no concept of latest, I demonstrated this on one of the calls, can repeat today. Essentially, it may have releases from different streams all mashed together without clear order. Similarly, for DT, it's just a flag, but sometimes it's not meaningful. I.e., a project supports 2 major or minor versions (in semver) at the same time, each of them has their own latest.

Possibly. Excuse my ignorance, and this is likely because I joined the effort so late, but where does the need to determine the "latest" component release stem from?

Component is an upstream dependency of Product. If there is a newer Component Release, as a developer / DevSecOps, I would like to migrate to that, especially if it has security updates.

So the full example is like this -

  1. I'm using library ACMElib v.1.1.0
  2. I want to know if there is a newer version available
  3. ACMElib just released v.1.1.1 (which is a security patch for v.1.1.0), as well as v.1.2.0 (which is a new feature release).
  4. I want TEA to inform me that v.1.1.1 is the one I can immediately upgrade to, while 1.2.0 is also there, but requires more testing since it's a feature update.

@nscuro
Copy link
Member

nscuro commented Jun 4, 2025

GitHub Releases has no concept of latest, I demonstrated this on one of the calls, can repeat today. Essentially, it may have releases from different streams all mashed together without clear order. Similarly, for DT, it's just a flag, but sometimes it's not meaningful.

Oh, I'm fully with you on that. It's not perfect, but it's one of those things that are "good enough" for most applications. It is more akin to "latest and greatest", instead of "latest of stream XYZ".

I.e., a project supports 2 major or minor versions (in semver) at the same time, each of them has their own latest.

What I have seen from TEA so far would also not cater to this (I may just have missed it). Are you arguing against having the concept of "latest" altogether? I think that would drastically simplify things.

If there is a newer Component Release, as a developer / DevSecOps, I would like to migrate to that, especially if it has security updates.

I would challenge if that is a use case TEA should cater to. There is already a vast array of tooling out there that informs about (and performs) version updates. A good chunk of versioning logic is different in each ecosystem, and even within those the rules are not always clear and fully enforced. IMO, TEA should act as a supplement to those (i.e. lookup more info about versions you're considering updating to).

I feel this inflates the TEA spec and deviates from it's primary goal (the exchange), but I respect if this is a direction the WG has decided TEA should go.

@taleodor
Copy link
Contributor

taleodor commented Jun 4, 2025

What I have seen from TEA so far would also not cater to this (I may just have missed it). Are you arguing against having the concept of "latest" altogether? I think that would drastically simplify things.

Yes, I don't think we should have the concept of latest. Container images supported it and it almost immediately became an anti-pattern. Instead, I believe we should keep the split between Component and Component Release and Product and Product Release. Then the API consumer would have options what to do with that (similar to the existing GitHub Releases workflow).

In the practical sense of this PR, it means that if a user searches for TEI without version, this leads to a Product that lists all available versions and not to some latest version. And it should work the same way for Components. Products and Components are not that different.

I would challenge if that is a use case TEA should cater to. There is already a vast array of tooling out there that informs about (and performs) version updates.

The novelty here is that TEA would have publisher supplying these data in a structured format. My understanding is that existing tooling should use publisher's TEA to make decisions rather than 3rd party heuristics. This is something that is better to discuss on the call though for establishing common approach.

@nscuro
Copy link
Member

nscuro commented Jun 4, 2025

In the practical sense of this PR, it means that if a user searches for TEI without version, this leads to a Product that lists all available versions and not to some latest version. And it should work the same way for Components. Products and Components are not that different.

Pragmatic, I like it.

Edit: I think the intention behind returning the "latest" version for a TEI without version is specifically for cases where a product doesn't really have a version. But I guess using a pseudo-version for such products would work just as well.

My understanding is that existing tooling should use publisher's TEA to make decisions rather than 3rd party heuristics.

If this is a goal then we should document it. I fear the tea-usecases.md doc may be horribly outdated at this point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hackathon Raised during OWASP Hackathon OpenAPI spec
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants