ce7cb702218693d08ea6d83464d2457c9250027c

This commit is contained in:
ms2k 2026-11-12 20:46:28 +09:00
commit 34c5f8963c
3 changed files with 145336 additions and 0 deletions

View file

@ -0,0 +1,51 @@
--- a/data/secscan_model/datatypes.py
+++ b/data/secscan_model/datatypes.py
@@ -94,7 +94,9 @@
Layer = namedtuple("Layer", ["Name", "NamespaceName", "ParentName", "IndexedByVersion", "Features"])
-class SecurityInformation(namedtuple("SecurityInformation", ["Layer"])):
+class SecurityInformation(
+ namedtuple("SecurityInformation", ["Layer", "Inventory"], defaults=(None,))
+):
"""
Canonical representation of security scan data for an image/manifest which is returned by the Quay API.
"""
@@ -146,11 +148,13 @@
)
for f in data_dict["Layer"].get("Features", [])
],
- )
+ ),
+ data_dict.get("Inventory"),
)
def to_dict(self):
return {
+ "Inventory": self.Inventory,
"Layer": {
"Name": self.Layer.Name,
"ParentName": self.Layer.ParentName,
--- a/data/secscan_model/secscan_v4_model.py
+++ b/data/secscan_model/secscan_v4_model.py
@@ -263,7 +263,19 @@
# TODO(alecmerdler): Provide a way to indicate the current scan is outdated (`report.state != status.indexer_hash`)
return SecurityInformationLookupResult.for_data(
- SecurityInformation(Layer(report["manifest_hash"], "", "", 4, features_for(report)))
+ SecurityInformation(
+ Layer(report["manifest_hash"], "", "", 4, features_for(report)),
+ {
+ key: report.get(key)
+ for key in (
+ "manifest_hash",
+ "packages",
+ "distributions",
+ "environments",
+ "repository",
+ )
+ },
+ )
)
def _get_manifest_iterator(

View file

@ -0,0 +1,31 @@
--- a/endpoints/web.py
+++ b/endpoints/web.py
@@ -873,7 +873,8 @@
if not features.ASSIGN_OAUTH_TOKEN:
abort(404)
- if not current_user.is_authenticated:
+ assigning_user = get_authenticated_user()
+ if not assigning_user:
abort(401)
user = get_nonrobot_user(username)
@@ -883,8 +884,7 @@
application = get_oauth_application_for_client_id(client_id)
if not application:
abort(404)
- current_db_user = current_user.db_user()
- if not is_org_admin(current_db_user, application.organization):
+ if not AdministerOrganizationPermission(application.organization.username).can():
abort(403)
assign_token_to_user(
@@ -899,7 +899,7 @@
"oauth_token_assigned",
application.organization.username,
{
- "assigning_user": current_db_user.username,
+ "assigning_user": assigning_user.username,
"assigned_user": user.username,
"application": application.name,
"client_id": application.client_id,

View file

@ -0,0 +1,41 @@
--- a/oauth/oidc.py
+++ b/oauth/oidc.py
@@ -26,7 +26,7 @@
OIDC_WELLKNOWN = ".well-known/openid-configuration"
PUBLIC_KEY_CACHE_TTL = 3600 # 1 hour
-ALLOWED_ALGORITHMS = ["RS256", "RS384"]
+ALLOWED_ALGORITHMS = ["RS256", "RS384", "EdDSA"]
JWT_CLOCK_SKEW_SECONDS = 30
@@ -490,13 +490,12 @@
except ValueError:
raise PublicKeyLoadException("Public key %s not found" % kid)
- if key_found.kty != "RSA":
- raise PublicKeyLoadException("No RSA form of public key %s not found" % kid)
+ if key_found.kty not in ("RSA", "OKP"):
+ raise PublicKeyLoadException("Unsupported public key type for %s" % kid)
- # Eyy, no more exporting/importing keys from PyCrypto to cryptography's format...
- rsa_key = key_found.as_key()
- self[kid] = rsa_key
- return rsa_key
+ public_key = key_found.as_key()
+ self[kid] = public_key
+ return public_key
def _load_keys_from_url(url, verify=True):
--- a/util/security/jwtutil.py
+++ b/util/security/jwtutil.py
@@ -27,7 +27,7 @@
# ALGORITHM_WHITELIST defines a whitelist of allowed algorithms to be used in JWTs. DO NOT ADD
# `none` here!
-ALGORITHM_WHITELIST = ["rs256", "hs256", "rs384"]
+ALGORITHM_WHITELIST = ["rs256", "hs256", "rs384", "eddsa"]
class _StrictJWT(PyJWT):