Skip to content

Commit

Permalink
Add new public json endpoint including OS Version (#3074)
Browse files Browse the repository at this point in the history
Fixes #3071
  • Loading branch information
jcristau committed Dec 18, 2023
1 parent 83e4fc5 commit e18b83a
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/auslib/web/public/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ def get_update(transaction, **parameters):
headers.update(get_content_signature_headers(response, ""))

return Response(response=response, status=200, headers=headers, mimetype="application/json")


get_update_1 = get_update
get_update_2 = get_update
19 changes: 18 additions & 1 deletion src/auslib/web/public/swagger/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ paths:

/json/1/{product}/{version}/{buildTarget}/{channel}/update.json:
get:
operationId: 'auslib.web.public.json.get_update'
operationId: 'auslib.web.public.json.get_update_1'
description: Return the appropriate update for the given parameters
produces:
- application/json
Expand All @@ -212,6 +212,23 @@ paths:
200:
description: Update response in JSON format

/json/2/{product}/{version}/{buildTarget}/{channel}/{osVersion}/update.json:
get:
operationId: 'auslib.web.public.json.get_update_2'
description: Return the appropriate update for the given parameters
produces:
- application/json
parameters:
- $ref: '#/parameters/product'
- $ref: '#/parameters/version'
- $ref: '#/parameters/buildTarget'
- $ref: '#/parameters/channel'
- $ref: '#/parameters/osVersion'
- $ref: '#/parameters/force'
responses:
200:
description: Update response in JSON format

/__heartbeat__:
get:
operationId: 'auslib.web.public.dockerflow.heartbeat'
Expand Down
171 changes: 167 additions & 4 deletions tests/web/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,33 @@ def guardian_db(db_schema):
}
}
}
"""
),
)
dbo.releases.t.insert().execute(
name="Guardian-0.6.0.0",
product="Guardian",
data_version=1,
data=createBlob(
"""
{
"name": "Guardian-0.6.0.0",
"product": "Guardian",
"schema_version": 10000,
"version": "0.6.0.0",
"required": true,
"hashFunction": "sha512",
"platforms": {
"WINNT_x86_64": {
"fileUrl": "https://good.com/0.6.0.0.msi",
"hashValue": "abcpqr"
},
"Darwin_x86_64": {
"fileUrl": "https://good.com/0.6.0.0.dmg",
"hashValue": "ghivwx"
}
}
}
"""
),
)
Expand Down Expand Up @@ -143,6 +170,15 @@ def guardian_db(db_schema):
version="<0.5.0.0",
data_version=1,
)
dbo.rules.t.insert().execute(
priority=110,
backgroundRate=100,
mapping="Guardian-0.6.0.0",
update_type="minor",
product="Guardian",
osVersion="obsolete",
data_version=1,
)
# fmt: off
# to force this on multiple lines
dbo.rules.t.insert().execute(
Expand Down Expand Up @@ -172,7 +208,7 @@ def guardian_db(db_schema):
update_type="minor",
product="Guardian",
channel="alpha",
osVersion="igonred",
osVersion="ignored",
buildID="12345",
locale="ignored",
memory="123",
Expand Down Expand Up @@ -224,7 +260,7 @@ def client():
("0.6.0.0", "Darwin_x86_64", "evilrelease", 200, {}),
],
)
def testGuardianResponse(client, version, buildTarget, channel, code, response):
def testGuardianResponseV1(client, version, buildTarget, channel, code, response):
ret = client.get(f"/json/1/Guardian/{version}/{buildTarget}/{channel}/update.json")
assert ret.status_code == code
if code == 200:
Expand Down Expand Up @@ -263,7 +299,7 @@ def testGuardianResponse(client, version, buildTarget, channel, code, response):
),
],
)
def testGuardianResponseWithoutSigning(client, version, buildTarget, channel, code, response):
def testGuardianResponseV1WithoutSigning(client, version, buildTarget, channel, code, response):
ret = client.get(f"/json/1/Guardian/{version}/{buildTarget}/{channel}/update.json")
assert ret.status_code == code
if code == 200:
Expand All @@ -284,7 +320,7 @@ def testGuardianResponseWithoutSigning(client, version, buildTarget, channel, co
(None, {"required": True, "url": "https://good.com/0.5.0.0.msi", "version": "0.5.0.0", "hashFunction": "sha512", "hashValue": "abcdef"}),
],
)
def testGuardianResponseWithGradualRollout(client, forceValue, response):
def testGuardianResponseV1WithGradualRollout(client, forceValue, response):
qs = {}
if forceValue:
qs["force"] = forceValue.query_value
Expand All @@ -294,3 +330,130 @@ def testGuardianResponseWithGradualRollout(client, forceValue, response):
assert ret.get_json() == response
assert ret.headers["Content-Signature"] == "x5u=https://this.is/a.x5u; p384ecdsa=abcdef"
auslib.web.public.helpers.make_hash.assert_called_once_with(ret.text)


@pytest.mark.usefixtures("appconfig", "guardian_db", "disable_errorhandler", "mock_autograph")
@pytest.mark.parametrize(
"version,buildTarget,channel,osVersion,code,response",
[
(
"0.4.0.0",
"WINNT_x86_64",
"release",
"Windows 10",
200,
{"required": True, "url": "https://good.com/0.5.0.0.msi", "version": "0.5.0.0", "hashFunction": "sha512", "hashValue": "abcdef"},
),
(
"0.5.0.0",
"WINNT_x86_64",
"release",
"current",
200,
{"required": True, "url": "https://good.com/1.0.0.0.msi", "version": "1.0.0.0", "hashFunction": "sha512", "hashValue": "mnopqr"},
),
(
"0.5.0.0",
"WINNT_x86_64",
"release",
"obsolete",
200,
{"required": True, "url": "https://good.com/0.6.0.0.msi", "version": "0.6.0.0", "hashFunction": "sha512", "hashValue": "abcpqr"},
),
(
"0.6.0.0",
"WINNT_x86_64",
"release",
"Windows 10",
200,
{"required": True, "url": "https://good.com/1.0.0.0.msi", "version": "1.0.0.0", "hashFunction": "sha512", "hashValue": "mnopqr"},
),
(
"0.99.99.99",
"WINNT_x86_64",
"release",
"Windows 10",
200,
{"required": True, "url": "https://good.com/1.0.0.0.msi", "version": "1.0.0.0", "hashFunction": "sha512", "hashValue": "mnopqr"},
),
("1.0.0.0", "WINNT_x86_64", "release", "Windows 10", 404, {}),
("0.6.0.0", "Linux_x86_64", "release", "Linux", 404, {}),
("0.6.0.0", "WINNT_x86_64", "beta", "Windows 10", 404, {}),
# This shouldn't match because the rule on the alpha channel contains fields not used by this type of update query.
("0.6.0.0", "WINNT_x86_64", "alpha", "Windows 10", 404, {}),
("0.6.0.0", "Darwin_x86_64", "evilrelease", "Darwin 13", 200, {}),
],
)
def testGuardianResponseV2(client, version, buildTarget, channel, osVersion, code, response):
ret = client.get(f"/json/2/Guardian/{version}/{buildTarget}/{channel}/{osVersion}/update.json")
assert ret.status_code == code
if code == 200:
assert ret.mimetype == "application/json"
assert ret.get_json() == response
assert ret.headers["Content-Signature"] == "x5u=https://this.is/a.x5u; p384ecdsa=abcdef"
auslib.web.public.helpers.make_hash.assert_called_once_with(ret.text)
assert "Rule-ID" in ret.headers
assert "Rule-Data-Version" in ret.headers


@pytest.mark.usefixtures("appconfig", "guardian_db", "disable_errorhandler")
@pytest.mark.parametrize(
"version,buildTarget,channel,osVersion,code,response",
[
(
"0.4.0.0",
"WINNT_x86_64",
"release",
"Windows 10",
200,
{"required": True, "url": "https://good.com/0.5.0.0.msi", "version": "0.5.0.0", "hashFunction": "sha512", "hashValue": "abcdef"},
),
(
"0.6.0.0",
"WINNT_x86_64",
"release",
"Windows 10",
200,
{"required": True, "url": "https://good.com/1.0.0.0.msi", "version": "1.0.0.0", "hashFunction": "sha512", "hashValue": "mnopqr"},
),
(
"0.99.99.99",
"WINNT_x86_64",
"release",
"Windows 10",
200,
{"required": True, "url": "https://good.com/1.0.0.0.msi", "version": "1.0.0.0", "hashFunction": "sha512", "hashValue": "mnopqr"},
),
],
)
def testGuardianResponseV2WithoutSigning(client, version, buildTarget, channel, osVersion, code, response):
ret = client.get(f"/json/2/Guardian/{version}/{buildTarget}/{channel}/{osVersion}/update.json")
assert ret.status_code == code
if code == 200:
assert ret.mimetype == "application/json"
assert ret.get_json() == response
assert "Content-Signature" not in ret.headers


@pytest.mark.usefixtures("appconfig", "guardian_db", "disable_errorhandler", "mock_autograph")
@pytest.mark.parametrize(
"forceValue,response",
[
(FORCE_MAIN_MAPPING, {"required": True, "url": "https://good.com/1.0.0.0.msi", "version": "1.0.0.0", "hashFunction": "sha512", "hashValue": "mnopqr"}),
(
FORCE_FALLBACK_MAPPING,
{"required": True, "url": "https://good.com/0.5.0.0.msi", "version": "0.5.0.0", "hashFunction": "sha512", "hashValue": "abcdef"},
),
(None, {"required": True, "url": "https://good.com/0.5.0.0.msi", "version": "0.5.0.0", "hashFunction": "sha512", "hashValue": "abcdef"}),
],
)
def testGuardianResponseV2WithGradualRollout(client, forceValue, response):
qs = {}
if forceValue:
qs["force"] = forceValue.query_value
ret = client.get("/json/2/Guardian/0.4.0.0/WINNT_x86_64/release-rollout/Windows%2010/update.json", query_string=qs)
assert ret.status_code == 200
assert ret.mimetype == "application/json"
assert ret.get_json() == response
assert ret.headers["Content-Signature"] == "x5u=https://this.is/a.x5u; p384ecdsa=abcdef"
auslib.web.public.helpers.make_hash.assert_called_once_with(ret.text)

0 comments on commit e18b83a

Please sign in to comment.