Validation Sets¶
Introduction¶
The Validation Sets API enables Validation Set assertions management.
All endpoints require a macaroon authenticated request with no special permissions.
See Macaroons for details on how to obtain a suitable macaroon for
interacting with this API. You could also use the surl
command line,
available as a snap:
snap install surl
to exercise this (and other) store APIs. The following example authenticates to the store and saves the macaroon locally for use in subsequent requests:
surl -a prod -s production -e <email> [[-p <macaroon_permission>]]
surl -a prod -X <http-method> https://dashboard.snapcraft.io/<endpoint>
[[-d '<json payload>']]
See surl help
for the details about these and other surl options.
The Validation Sets API is exposed at the following base URLs:
Staging: https://dashboard.staging.snapcraft.io/api/v2/validation-sets
Production: https://dashboard.snapcraft.io/api/v2/validation-sets
Response Format¶
JSON will be returned in all responses from the API, including error responses, please refer to the following section for details about the format.
Prepare Validation Set assertion headers ready for signing.¶
Introduced in version 16
- POST /api/v2/validation-sets/build-assertion¶
Prepare Validation Set headers for local signing.
Return Validation Set assertion headers ready for local signing by the publisher.
- reqheader Authorization
macaroon authorization header for an active user
- status 200
success
- status 400
error
- status 401
authentication required
Usage¶
As mentioned in the introduction, this endpoint can be exercised using the
surl
command as follows:
surl -s production -e your-email@example.com -X POST
https://dashboard.snapcraft.io/api/v2/validation-sets/build-assertion
-d '<input-data-as-json>'
where your-email@example.com
has to be an existing account.
Example¶
Prepare assertion headers for a validation set named “acme-cert-2020-10”.
Request:
POST /api/v2/validation-sets/build-assertion HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json
{
"name": "acme-cert-2020-10",
"account-id": "AccountIDXXXOfTheRequestingUserX",
"sequence": 3,
"snaps": [
{
"name": "snap-name-1",
"presence": "optional"
},
{
"name": "snap-name-2"
},
{
"name": "snap-name-3",
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"presence": "required",
"revision": 2
},
{
"name": "snap-name-4",
"revision": 123
},
{
"name": "snap-name-5",
"presence": "invalid"
}
]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "acme-cert-2020-10",
"revision": "20",
"sequence": "3",
"series": "16",
"snaps": [
{
"id": "XXSnapIDForXSnapName1XXXXXXXXXXX",
"name": "snap-name-1",
"presence": "optional"
},
{
"id": "XXSnapIDForXSnapName2XXXXXXXXXXX",
"name": "snap-name-2"
},
{
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"name": "snap-name-3",
"presence": "required",
"revision": "2"
},
{
"id": "XXSnapIDForXSnapName4XXXXXXXXXXX",
"name": "snap-name-4",
"revision": "123"
},
{
"id": "XXSnapIDForXSnapName5XXXXXXXXXXX",
"name": "snap-name-5",
"presence": "invalid"
}
],
"timestamp": "2020-11-04T14:53:47Z",
"type": "validation-set"
}
Errors¶
Request payload contains a number of request JSON schema violations.
Request:
POST /api/v2/validation-sets/build-assertion HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json
{
"surprise-field": 123,
"name": "too-long-name...",
"sequence": 0,
"snaps": [
{
"name": "snap-name-1",
"presence": "nice-to-have"
},
{
"name": "snap-name-2",
"revision": -1
}
]
}
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"message": "Additional properties are not allowed ('surprise-field' was unexpected) at /",
"code": "invalid-request"
},
{
"message": "'too-long-name...' is too long at /name",
"code": "invalid-request"
},
{
"message": "0 is less than the minimum of 1 at /sequence",
"code": "invalid-request"
},
{
"message": "'nice-to-have' is not one of ['required', 'optional', 'invalid'] at /snaps/0/presence",
"code": "invalid-request"
},
{
"message": "-1 is less than the minimum of 0 at /snaps/1/revision",
"code": "invalid-request"
},
{
"message": "'account-id' is a required property at /",
"code": "invalid-request"
}
]
}
Requested sequence number is too high for an assertion with a given name.
Request:
POST /api/v2/validation-sets/build-assertion HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json
{
"name": "acme-cert-2020-10",
"account-id": "AccountIDXXXOfTheRequestingUserX",
"sequence": 3050,
"snaps": [
{
"name": "snap-name-1"
},
{
"name": "snap-name-2"
}
]
}
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"code": "invalid-field",
"extra": {
"field": "sequence",
"value": 3050
},
"message": "The validation-set sequence 3050 is not valid: sequence should not be higher than 2."
}
]
}
Requested validation set name “latest” is invalid.
Request:
POST /api/v2/validation-sets/build-assertion HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json
{
"name": "latest",
"account-id": "AccountIDXXXOfTheRequestingUserX",
"sequence": 3,
"snaps": [
{
"name": "snap-name-1"
},
{
"name": "snap-name-2"
}
]
}
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"code": "invalid-field",
"extra": {
"field": "name",
"value": "latest"
},
"message": "The validation-set name 'latest' is not valid: 'latest' is reserved."
}
]
}
List of snaps contains some snaps that do not exist, or the account does not have access to, or snaps that were never released, or were paired with incorrect snap IDs.
Request:
POST /api/v2/validation-sets/build-assertion HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json
{
"name": "acme-final-vs",
"account-id": "AccountIDXXXOfTheRequestingUserX",
"sequence": 3,
"snaps": [
{
"name": "snap-name-1"
},
{
"name": "snap-name-x"
},
{
"id": "XXSnapIDForXSnapNameYXXXXXXXXXXX",
"name": "snap-name-y"
}
]
}
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"extra": {
"value": [
{
"name": "snap-name-1"
},
{
"name": "snap-name-x"
},
{
"id": "XXSnapIDForXSnapNameYXXXXXXXXXXX",
"name": "snap-name-y"
}
],
"missing": [
{
"name": "snap-name-x"
},
{
"id": "XXSnapIDForXSnapNameYXXXXXXXXXXX",
"name": "snap-name-y"
}
],
"field": "snaps"
},
"message": "List of snap names that either do not exist, or the account does not have access to, or snaps that were never released, or were paired with incorrect snap IDs: ['snap-name-x', 'snap-name-y'].",
"code": "invalid-field"
}
]
}
List of snaps contains some snaps or snap/revision pairs for which no approved revisions exist.
Request:
POST /api/v2/validation-sets/build-assertion HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/json
{
"name": "acme-final-vs",
"account-id": "AccountIDXXXOfTheRequestingUserX",
"sequence": 3,
"snaps": [
{
"name": "snap-name-1"
},
{
"name": "snap-name-x",
},
{
"id": "XXSnapIDForXSnapNameYXXXXXXXXXXX",
"name": "snap-name-y",
"revision": 42
}
]
}
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"extra": {
"value": [
{
"name": "snap-name-1"
},
{
"name": "snap-name-x",
},
{
"id": "XXSnapIDForXSnapNameYXXXXXXXXXXX",
"name": "snap-name-y",
"revision": 42
}
],
"missing": [
{
"name": "snap-name-x",
},
{
"id": "XXSnapIDForXSnapNameYXXXXXXXXXXX",
"name": "snap-name-y",
"revision": 42
}
],
"field": "snaps"
},
"message": "No approved snap revision exist for snaps: ['snap-name-x', 'snap-name-y'].",
"code": "invalid-field"
}
]
}
Changelog¶
Version 16: New API endpoints for Validation Sets management.
Request JSON Schema¶
{
"additionalProperties": false,
"properties": {
"account-id": {
"description": "Issuer of the Validation Set",
"maxLength": 100,
"type": "string"
},
"name": {
"description": "Validation Set name",
"maxLength": 100,
"type": "string"
},
"sequence": {
"description": "Validation Set sequence",
"minimum": 1,
"type": "integer"
},
"snaps": {
"items": {
"additionalProperties": false,
"description": "List of snaps in a Validation Set assertion",
"properties": {
"components": {
"additionalProperties": false,
"description": "Snap components",
"patternProperties": {
"^[a-z0-9](?:-?[a-z0-9])*$": {
"oneOf": [
{
"description": "Snap component presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"presence": {
"description": "Snap component presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
"revision": {
"description": "Snap component revision",
"minimum": 1,
"type": "integer"
}
},
"type": "object"
}
]
}
},
"type": "object"
},
"id": {
"description": "Snap ID",
"maxLength": 100,
"type": "string"
},
"name": {
"description": "Snap name",
"maxLength": 100,
"type": "string"
},
"presence": {
"description": "Snap presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
"revision": {
"description": "Snap revision",
"minimum": 0,
"type": "integer"
}
},
"required": [
"name"
],
"type": "object"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"account-id",
"name",
"sequence",
"snaps"
],
"type": "object"
}
Response JSON Schema¶
{
"additionalProperties": false,
"properties": {
"account-id": {
"description": "The \"account-id\" assertion header",
"type": "string"
},
"authority-id": {
"description": "The \"authority-id\" assertion header",
"type": "string"
},
"name": {
"description": "The \"name\" assertion header",
"type": "string"
},
"revision": {
"description": "The \"revision\" assertion header",
"type": "string"
},
"sequence": {
"description": "The \"sequence\" assertion header",
"type": "string"
},
"series": {
"description": "The \"series\" assertion header",
"type": "string"
},
"snaps": {
"items": {
"additionalProperties": false,
"description": "List of snaps in a Validation Set assertion",
"properties": {
"components": {
"additionalProperties": false,
"description": "Snap components",
"patternProperties": {
"^[a-z0-9](?:-?[a-z0-9])*$": {
"oneOf": [
{
"description": "Snap component presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"presence": {
"description": "Snap component presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
"revision": {
"description": "Snap component revision",
"type": "string"
}
},
"type": "object"
}
]
}
},
"type": "object"
},
"id": {
"description": "Snap ID",
"maxLength": 100,
"type": "string"
},
"name": {
"description": "Snap name",
"maxLength": 100,
"type": "string"
},
"presence": {
"description": "Snap presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
"revision": {
"description": "Snap revision",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"minItems": 1,
"type": "array"
},
"timestamp": {
"description": "The \"timestamp\" assertion header",
"type": "string"
},
"type": {
"const": "validation-set",
"description": "The \"type\" assertion header",
"type": "string"
}
},
"required": [
"type",
"authority-id",
"series",
"account-id",
"name",
"sequence",
"revision",
"timestamp",
"snaps"
],
"type": "object"
}
Manage account’s validation-set assertions.¶
Introduced in version 16
- GET /api/v2/validation-sets/(?P<name>[\\w-]+)¶
- POST /api/v2/validation-sets/(?P<name>[\\w-]+)¶
Manage account’s validation-set assertions.
Usage¶
As mentioned in the introduction, this endpoint can be exercised using the
surl
command as follows:
surl -s production -e your-email@example.com -X GET
https://dashboard.snapcraft.io/api/v2/validation-sets
where your-email@example.com
has to be an existing account.
- GET /api/v2/validation-sets[/<name>]¶
- reqheader Authorization
macaroon authorization header for a registered user
- status 200
success
- status 400
error
- status 401
authentication required
GET requests to
/api/v2/validation-sets
and/api/v2/validation-sets/<name>
,
return a list of headers for validation set assertions registered by the requesting user, that match requested criteria.
By default, a GET request to /api/v2/validation-sets
returns headers
for all validation sets owned by the requesting account, each at their
latest sequence and latest revision. The same applies to
/api/v2/validation-sets/<name>
, except that the result will contain
headers for one specific assertion.
In both cases
sequence=all
query parameter can be added to request all sequences of the relevant assertions at their latest revisions.sequence=latest
query parameter is also supported (this is the default behavior).
The /api/v2/validation-sets/<name>
endpoint additionally supports a
sequence=N
query parameter, where N
is a specific sequence number.
GET Examples¶
Empty response: no validation sets found.
Request:
GET /api/v2/validation-sets/science-set?sequence=1 HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"assertions": []
}
Fetch all (2 in this example) validation set assertions owned by the requesting account, at their latest sequence and revision.
Request:
GET /api/v2/validation-sets HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"assertions": [
{
"headers": {
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "certification-x1",
"revision": "222",
"sequence": "9",
"series": "16",
"sign-key-sha3-384": "XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"snaps": [
{
"id": "XXSnapIDForXSnapName1XXXXXXXXXXX",
"name": "snap-name-1",
"presence": "optional"
},
{
"id": "XXSnapIDForXSnapName2XXXXXXXXXXX",
"name": "snap-name-2"
}
],
"timestamp": "2020-10-29T16:36:56Z",
"type": "validation-set"
}
},
{
"headers": {
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "acme-qa",
"revision": "2",
"sequence": "2",
"series": "16",
"sign-key-sha3-384": "XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"snaps": [
{
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"name": "snap-name-3",
"presence": "required",
"revision": "2"
}
],
"timestamp": "2020-10-29T16:36:56Z",
"type": "validation-set"
}
}
]
}
Fetch all sequences of the “acme-qa” validation set at their latest revisions.
Request:
GET /api/v2/validation-sets/acme-qa?sequence=all HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"assertions": [
{
"headers": {
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "acme-qa",
"revision": "2",
"sequence": "2",
"series": "16",
"sign-key-sha3-384": "XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"snaps": [
{
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"name": "snap-name-3",
"presence": "required",
"revision": "20"
}
],
"timestamp": "2020-10-29T16:36:56Z",
"type": "validation-set"
}
},
{
"headers": {
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "acme-qa",
"revision": "1",
"sequence": "1",
"series": "16",
"sign-key-sha3-384": "XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"snaps": [
{
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"name": "snap-name-3",
"revision": "10"
}
],
"timestamp": "2020-10-29T16:36:56Z",
"type": "validation-set"
}
}
]
}
Fetch the latest sequence of the “acme-qa” validation set at its latest revision.
Request:
GET /api/v2/validation-sets/acme-qa?sequence=latest HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"assertions": [
{
"headers": {
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "acme-qa",
"revision": "2",
"sequence": "2",
"series": "16",
"sign-key-sha3-384": "XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"snaps": [
{
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"name": "snap-name-3",
"presence": "required",
"revision": "20"
}
],
"timestamp": "2020-10-29T16:36:56Z",
"type": "validation-set"
}
}
]
}
GET Errors¶
Invalid numeric sequence
query parameter value for the general variant (no
name specified) of the endpoint.
Request:
GET /api/v2/validation-sets?sequence=22 HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"code": "invalid-sequence-filter",
"extra": {
"field": "sequence"
},
"message": "sequence must be one of ['all', 'latest']"
}
]
}
Invalid sequence
query parameter value for the specific validation set name
variant of the endpoint.
Request:
GET /api/v2/validation-sets/acme-qa?sequence=forty-two HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"message": "sequence must be one of ['all', 'latest'] or a positive integer higher than 0",
"code": "invalid-sequence-filter",
"extra": {
"field": "sequence"
}
}
]
}
- POST /api/v2/validation-sets¶
- reqheader Authorization
macaroon authorization header for a registered user
- status 201
success
- status 400
error
- status 409
conflict
- status 401
authentication required
POST requests to /api/v2/validation-sets
are used to register new
validation set assertions with the store.
The endpoint expects a valid validation-set type assertion, signed with a
signing key registered with the store. The endpoint expects an
x.ubuntu.assertion
content-type request.
/api/v2/validation-sets/build-assertion
endpoint can be used to obtain
validation-set assertion headers as JSON, to be used as an input to
snap sign
, which will sign the assertion and output it in the
x.ubuntu.assertion
format, ready for sending to
/api/v2/validation-sets
in a POST request.
POST Examples¶
Register a self signed validation set assertion.
Request:
POST /api/v2/validation-sets HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/x.ubuntu.assertion
type: validation-set
authority-id: AccountIDXXXOfTheRequestingUserX
revision: 2
series: 16
account-id: AccountIDXXXOfTheRequestingUserX
name: acme-bits
sequence: 2
snaps:
-
id: XXSnapIDForXSnapName1XXXXXXXXXXX
name: snap-name-1
presence: optional
-
id: XXSnapIDForXSnapName3XXXXXXXXXXX
name: snap-name-3
presence: required
revision: 20
timestamp: 2020-10-29T16:36:56Z
sign-key-sha3-384: XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ASignatureXAHRYhBLdCTW+zo7oGALa88HYj3UQq+srnBQJfoTiDAAoJEHYj3UQq+srnGS0P/1Hx
53VBM0SignatureX29ub5nN3lCZTSx1uCsAu8/hyR25iYOKcvHu8Rhvdc3T73skb+Zjk9HDtPnRa
no0UCM6lq8pSignatureXJ37vm34RF8E44iXxex8LM26A/kRrXO1q6hELacUB1wL6Obnni2+stQQ
Lm93C/PP9Hd54YQ1SignatureXCuvuzp5x/YaDgKA6UtHFe3QpNcFYpxflMCLmq6vbWi8hTybJKu
0wf+8cUeYaDm1E0+KP+3ySignatureXSignatureXxxm6qYiOEkIvN3jfLyarcFT8OEdjsr/vj32
rdpqPJXGTQcRJrKNGjEJmF9INnSignatureXGMfjFFw96uQlBJiy6RCa5AxVcY3D2xtJ8YJBH1eo
fwojpbg6XJgaexouAis3hQbo2AsCaZNSignatureXpcqdFQSWXI+ni84IkhD8o+YtvRHwRA+LmVC
Rg7Q6Lau9v3gWCplp1lIgogqsi3ZLqLciYzrSignatureXNXqMgOsQ/sAgjoeIuHFvBEnPPB3iWl
O4uRHNmMRI0jPeDhN94I+rL/EoV/kRmM7jIznP/41SignatureXdqVo0VqLnHcX0pw0x5jqp2Toc
s81q2i53AMgPS7FFhCV80ItTvqYFgN4nEtGttK960I7hTESignatureXCDFaNiKlMUPiE4w3
Response:
HTTP/1.1 201 Created
Content-Type: application/json
{
"assertions": [
{
"headers": {
"account-id": "AccountIDXXXOfTheRequestingUserX",
"authority-id": "AccountIDXXXOfTheRequestingUserX",
"name": "acme-qa",
"revision": "2",
"sequence": "2",
"series": "16",
"sign-key-sha3-384": "XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"snaps": [
{
"id": "XXSnapIDForXSnapName1XXXXXXXXXXX",
"name": "snap-name-1",
"presence": "optional"
},
{
"id": "XXSnapIDForXSnapName3XXXXXXXXXXX",
"name": "snap-name-3",
"presence": "required",
"revision": "20"
}
],
"timestamp": "2020-10-29T16:36:56Z",
"type": "validation-set"
}
}
]
}
POST Errors¶
Attempt at registering an already existing revision of a validation set results in an HTTP 409 response.
Request:
POST /api/v2/validation-sets HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/x.ubuntu.assertion
type: validation-set
authority-id: AccountIDXXXOfTheRequestingUserX
revision: 1
series: 16
account-id: AccountIDXXXOfTheRequestingUserX
name: acme-bits
sequence: 2
snaps:
-
id: XXSnapIDForXSnapName1XXXXXXXXXXX
name: snap-name-1
presence: optional
-
id: XXSnapIDForXSnapName3XXXXXXXXXXX
name: snap-name-3
presence: required
revision: 13
timestamp: 2020-10-29T16:36:56Z
sign-key-sha3-384: XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ASignatureXAHRYhBLdCTW+zo7oGALa88HYj3UQq+srnBQJfoTiDAAoJEHYj3UQq+srnGS0P/1Hx
53VBM0SignatureX29ub5nN3lCZTSx1uCsAu8/hyR25iYOKcvHu8Rhvdc3T73skb+Zjk9HDtPnRa
no0UCM6lq8pSignatureXJ37vm34RF8E44iXxex8LM26A/kRrXO1q6hELacUB1wL6Obnni2+stQQ
Lm93C/PP9Hd54YQ1SignatureXCuvuzp5x/YaDgKA6UtHFe3QpNcFYpxflMCLmq6vbWi8hTybJKu
0wf+8cUeYaDm1E0+KP+3ySignatureXSignatureXxxm6qYiOEkIvN3jfLyarcFT8OEdjsr/vj32
rdpqPJXGTQcRJrKNGjEJmF9INnSignatureXGMfjFFw96uQlBJiy6RCa5AxVcY3D2xtJ8YJBH1eo
fwojpbg6XJgaexouAis3hQbo2AsCaZNSignatureXpcqdFQSWXI+ni84IkhD8o+YtvRHwRA+LmVC
Rg7Q6Lau9v3gWCplp1lIgogqsi3ZLqLciYzrSignatureXNXqMgOsQ/sAgjoeIuHFvBEnPPB3iWl
O4uRHNmMRI0jPeDhN94I+rL/EoV/kRmM7jIznP/41SignatureXdqVo0VqLnHcX0pw0x5jqp2Toc
s81q2i53AMgPS7FFhCV80ItTvqYFgN4nEtGttK960I7hTESignatureXCDFaNiKlMUPiE4w3
Response:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error-list": [
{
"code": "conflict",
"message": "Assertion request not valid: \"could not add assertion (revision 1 is already the current revision)\"."
}
]
}
List of snaps contains some snaps that do not exist, or the account does not have access to, or snaps that were never released, or were paired with incorrect snap IDs.
Request:
POST /api/v2/validation-sets HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/x.ubuntu.assertion
type: validation-set
authority-id: AccountIDXXXOfTheRequestingUserX
revision: 1
series: 16
account-id: AccountIDXXXOfTheRequestingUserX
name: acme-bits
sequence: 2
snaps:
-
id: XXSnapIDForXSnapName1XXXXXXXXXXX
name: snap-name-1
-
id: XXSnapIDForXSnapNameXXXXXXXXXXXX
name: snap-name-x
timestamp: 2020-10-28T11:11:11Z
sign-key-sha3-384: XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ASignatureXAHRYhBLdCTW+zo7oGALa88HYj3UQq+srnBQJfoTiDAAoJEHYj3UQq+srnGS0P/1Hx
53VBM0SignatureX29ub5nN3lCZTSx1uCsAu8/hyR25iYOKcvHu8Rhvdc3T73skb+Zjk9HDtPnRa
no0UCM6lq8pSignatureXJ37vm34RF8E44iXxex8LM26A/kRrXO1q6hELacUB1wL6Obnni2+stQQ
Lm93C/PP9Hd54YQ1SignatureXCuvuzp5x/YaDgKA6UtHFe3QpNcFYpxflMCLmq6vbWi8hTybJKu
0wf+8cUeYaDm1E0+KP+3ySignatureXSignatureXxxm6qYiOEkIvN3jfLyarcFT8OEdjsr/vj32
rdpqPJXGTQcRJrKNGjEJmF9INnSignatureXGMfjFFw96uQlBJiy6RCa5AxVcY3D2xtJ8YJBH1eo
fwojpbg6XJgaexouAis3hQbo2AsCaZNSignatureXpcqdFQSWXI+ni84IkhD8o+YtvRHwRA+LmVC
Rg7Q6Lau9v3gWCplp1lIgogqsi3ZLqLciYzrSignatureXNXqMgOsQ/sAgjoeIuHFvBEnPPB3iWl
O4uRHNmMRI0jPeDhN94I+rL/EoV/kRmM7jIznP/41SignatureXdqVo0VqLnHcX0pw0x5jqp2Toc
s81q2i53AMgPS7FFhCV80ItTvqYFgN4nEtGttK960I7hTESignatureXCDFaNiKlMUPiE4w3
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"extra": {
"value": [
{
"id": "XXSnapIDForXSnapName1XXXXXXXXXXX",
"name": "snap-name-1"
},
{
"id": "XXSnapIDForXSnapNameXXXXXXXXXXXX",
"name": "snap-name-x"
}
],
"missing": [
{
"id": "XXSnapIDForXSnapNameXXXXXXXXXXXX",
"name": "snap-name-x"
}
],
"field": "snaps"
},
"message": "List of snap names that either do not exist, or the account does not have access to, or snaps that were never released, or were paired with incorrect snap IDs: ['snap-name-x'].",
"code": "invalid-field"
}
]
}
Assertion’s “account-id” header does not match its “authority-id” header.
Request:
POST /api/v2/validation-sets HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/x.ubuntu.assertion
type: validation-set
authority-id: AccountIDXXXOfTheRequestingUserX
revision: 1
series: 16
account-id: AccountIDXYZOfDifferentUserXYZXY
name: acme-bits
sequence: 2
snaps:
-
id: XXSnapIDForXSnapName1XXXXXXXXXXX
name: snap-name-1
timestamp: 2020-10-28T11:11:11Z
sign-key-sha3-384: XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ASignatureXAHRYhBLdCTW+zo7oGALa88HYj3UQq+srnBQJfoTiDAAoJEHYj3UQq+srnGS0P/1Hx
53VBM0SignatureX29ub5nN3lCZTSx1uCsAu8/hyR25iYOKcvHu8Rhvdc3T73skb+Zjk9HDtPnRa
no0UCM6lq8pSignatureXJ37vm34RF8E44iXxex8LM26A/kRrXO1q6hELacUB1wL6Obnni2+stQQ
Lm93C/PP9Hd54YQ1SignatureXCuvuzp5x/YaDgKA6UtHFe3QpNcFYpxflMCLmq6vbWi8hTybJKu
0wf+8cUeYaDm1E0+KP+3ySignatureXSignatureXxxm6qYiOEkIvN3jfLyarcFT8OEdjsr/vj32
rdpqPJXGTQcRJrKNGjEJmF9INnSignatureXGMfjFFw96uQlBJiy6RCa5AxVcY3D2xtJ8YJBH1eo
fwojpbg6XJgaexouAis3hQbo2AsCaZNSignatureXpcqdFQSWXI+ni84IkhD8o+YtvRHwRA+LmVC
Rg7Q6Lau9v3gWCplp1lIgogqsi3ZLqLciYzrSignatureXNXqMgOsQ/sAgjoeIuHFvBEnPPB3iWl
O4uRHNmMRI0jPeDhN94I+rL/EoV/kRmM7jIznP/41SignatureXdqVo0VqLnHcX0pw0x5jqp2Toc
s81q2i53AMgPS7FFhCV80ItTvqYFgN4nEtGttK960I7hTESignatureXCDFaNiKlMUPiE4w3
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"code": "invalid-request",
"message": "account-id and authority-id must match the requesting user."
}
]
}
Assertion’s signing key is not registered with the store.
Request:
POST /api/v2/validation-sets HTTP/1.1
Host: dashboard.snapcraft.io
Authorization: Macaroon root=..., discharge=...
Content-Type: application/x.ubuntu.assertion
type: validation-set
authority-id: AccountIDXXXOfTheRequestingUserX
revision: 1
series: 16
account-id: AccountIDXXXOfTheRequestingUserX
name: acme-bits
sequence: 2
snaps:
-
id: XXSnapIDForXSnapName1XXXXXXXXXXX
name: snap-name-1
timestamp: 2020-10-28T11:11:11Z
sign-key-sha3-384: XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ASignatureXAHRYhBLdCTW+zo7oGALa88HYj3UQq+srnBQJfoTiDAAoJEHYj3UQq+srnGS0P/1Hx
53VBM0SignatureX29ub5nN3lCZTSx1uCsAu8/hyR25iYOKcvHu8Rhvdc3T73skb+Zjk9HDtPnRa
no0UCM6lq8pSignatureXJ37vm34RF8E44iXxex8LM26A/kRrXO1q6hELacUB1wL6Obnni2+stQQ
Lm93C/PP9Hd54YQ1SignatureXCuvuzp5x/YaDgKA6UtHFe3QpNcFYpxflMCLmq6vbWi8hTybJKu
0wf+8cUeYaDm1E0+KP+3ySignatureXSignatureXxxm6qYiOEkIvN3jfLyarcFT8OEdjsr/vj32
rdpqPJXGTQcRJrKNGjEJmF9INnSignatureXGMfjFFw96uQlBJiy6RCa5AxVcY3D2xtJ8YJBH1eo
fwojpbg6XJgaexouAis3hQbo2AsCaZNSignatureXpcqdFQSWXI+ni84IkhD8o+YtvRHwRA+LmVC
Rg7Q6Lau9v3gWCplp1lIgogqsi3ZLqLciYzrSignatureXNXqMgOsQ/sAgjoeIuHFvBEnPPB3iWl
O4uRHNmMRI0jPeDhN94I+rL/EoV/kRmM7jIznP/41SignatureXdqVo0VqLnHcX0pw0x5jqp2Toc
s81q2i53AMgPS7FFhCV80ItTvqYFgN4nEtGttK960I7hTESignatureXCDFaNiKlMUPiE4w3
Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error-list": [
{
"code": "invalid-request",
"message": "Assertion request not valid: \"could not validate assertion (no matching public key \"XSignXKeyXHashXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\" for signature by \"AccountIDXXXOfTheRequestingUserX\")\"."
}
]
}
Changelog¶
Version 16: New API endpoints for Validation Sets management.
Response JSON Schema¶
{
"additionalProperties": false,
"properties": {
"assertions": {
"description": "List of validation-set assertions",
"items": {
"additionalProperties": false,
"properties": {
"headers": {
"additionalProperties": false,
"description": "Assertion headers",
"properties": {
"account-id": {
"description": "The \"account-id\" assertion header",
"type": "string"
},
"authority-id": {
"description": "The \"authority-id\" assertion header",
"type": "string"
},
"name": {
"description": "The \"name\" assertion header",
"type": "string"
},
"revision": {
"description": "The \"revision\" assertion header",
"type": "string"
},
"sequence": {
"description": "The \"sequence\" assertion header",
"type": "string"
},
"series": {
"description": "The \"series\" assertion header",
"type": "string"
},
"sign-key-sha3-384": {
"description": "Signing key ID",
"type": "string"
},
"snaps": {
"items": {
"additionalProperties": false,
"description": "List of snaps in a Validation Set assertion",
"properties": {
"components": {
"additionalProperties": false,
"description": "Snap components",
"patternProperties": {
"^[a-z0-9](?:-?[a-z0-9])*$": {
"oneOf": [
{
"description": "Snap component presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"presence": {
"description": "Snap component presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
"revision": {
"description": "Snap component revision",
"type": "string"
}
},
"type": "object"
}
]
}
},
"type": "object"
},
"id": {
"description": "Snap ID",
"maxLength": 100,
"type": "string"
},
"name": {
"description": "Snap name",
"maxLength": 100,
"type": "string"
},
"presence": {
"description": "Snap presence",
"enum": [
"required",
"optional",
"invalid"
],
"type": "string"
},
"revision": {
"description": "Snap revision",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"minItems": 1,
"type": "array"
},
"timestamp": {
"description": "The \"timestamp\" assertion header",
"type": "string"
},
"type": {
"const": "validation-set",
"description": "The \"type\" assertion header",
"type": "string"
}
},
"required": [
"type",
"authority-id",
"series",
"account-id",
"name",
"sequence",
"snaps",
"sign-key-sha3-384",
"timestamp"
],
"type": "object"
}
},
"required": [
"headers"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"assertions"
],
"type": "object"
}