Comparing version 0.4.0 to 0.5.0
{ | ||
"name": "oso-cloud", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Client library for Oso Cloud", | ||
@@ -8,7 +8,20 @@ "main": "src/client.js", | ||
"scripts": { | ||
"test": "node ./src/client.test.js" | ||
"lint": "eslint", | ||
"test": "jest", | ||
"prettier:check": "prettier --check \"**/*.{js,ts,tsx,json}\"", | ||
"prettier": "prettier --write \"**/*.{js,ts,tsx,json}\"" | ||
}, | ||
"dependencies": { | ||
"node-fetch": "^2.6.7" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^8.0.1", | ||
"eslint-config-standard": "^17.0.0", | ||
"eslint-plugin-import": "^2.25.2", | ||
"eslint-plugin-jest": "^26.2.2", | ||
"eslint-plugin-n": "^15.0.0", | ||
"eslint-plugin-promise": "^6.0.0", | ||
"jest": "^28.1", | ||
"prettier": "^2.6.2" | ||
} | ||
} |
@@ -28,3 +28,3 @@ const { URLSearchParams } = require("url"); | ||
this.url = url || "https://cloud.osohq.com"; | ||
this.token = apiKey | ||
this.token = apiKey; | ||
} | ||
@@ -48,2 +48,39 @@ | ||
async authorize_resources(actor, action, resources) { | ||
function key(e) { | ||
return `${e.type}:${e.id}`; | ||
} | ||
const { type: actorType, id: actorId } = extractTypedId(actor); | ||
if (typeof action !== "string") { | ||
throw new TypeError(`'action' should be a string: ${action}`); | ||
} | ||
if (!resources || resources.length === 0) { | ||
return []; | ||
} | ||
const resourcesExtracted = resources.map((r) => extractTypedId(r)); | ||
const { results } = await this.POST("authorize_resources", { | ||
actor_type: actorType, | ||
actor_id: actorId, | ||
action, | ||
resources: resourcesExtracted, | ||
}); | ||
if (results.length == 0) { | ||
return []; | ||
} | ||
const resultsLookup = {}; | ||
for (let i = 0, len = results.length; i < len; ++i) { | ||
let k = key(results[i]); | ||
if (!resultsLookup[k]) { | ||
resultsLookup[k] = true; | ||
} | ||
} | ||
return resources.filter((r) => resultsLookup[key(extractTypedId(r))]); | ||
} | ||
async list(actor, action, resourceType) { | ||
@@ -76,2 +113,14 @@ const { type: actor_type, id: actor_id } = extractTypedId(actor); | ||
async actions(actor, resource) { | ||
const { type: actor_type, id: actor_id } = extractTypedId(actor); | ||
const { type: resource_type, id: resource_id } = extractTypedId(resource); | ||
const { results } = await this.POST("actions", { | ||
actor_type, | ||
actor_id, | ||
resource_type, | ||
resource_id, | ||
}); | ||
return results; | ||
} | ||
policy(src) { | ||
@@ -84,3 +133,3 @@ return this.POST("policy", { src }); | ||
predicate, | ||
args: args.map(extractTypedId) | ||
args: args.map(extractTypedId), | ||
}); | ||
@@ -92,3 +141,3 @@ } | ||
predicate, | ||
args: args.map(extractTypedId) | ||
args: args.map(extractTypedId), | ||
}); | ||
@@ -98,8 +147,7 @@ } | ||
bulkTell(facts) { | ||
return this.POST("bulk_load", | ||
facts.map( | ||
([predicate, ...args]) => { | ||
return ({predicate, args: args.map(extractTypedId)}) | ||
} | ||
) | ||
return this.POST( | ||
"bulk_load", | ||
facts.map(([predicate, ...args]) => { | ||
return { predicate, args: args.map(extractTypedId) }; | ||
}) | ||
); | ||
@@ -109,17 +157,15 @@ } | ||
bulkDelete(facts) { | ||
return this.POST("bulk_delete", | ||
facts.map( | ||
([predicate, ...args]) => { | ||
return ({predicate, args: args.map(extractTypedId)}) | ||
} | ||
) | ||
return this.POST( | ||
"bulk_delete", | ||
facts.map(([predicate, ...args]) => { | ||
return { predicate, args: args.map(extractTypedId) }; | ||
}) | ||
); | ||
} | ||
get(predicate, ...args) { | ||
const params = { predicate }; | ||
args.map(extractArgQuery).forEach(({ type, id }, i) => { | ||
params[`args.${i}.type`] = type; | ||
params[`args.${i}.id`] = id; | ||
if (type !== undefined) params[`args.${i}.type`] = type; | ||
if (id !== undefined) params[`args.${i}.id`] = id; | ||
}); | ||
@@ -133,4 +179,4 @@ return this.GET("facts", params); | ||
return fetch(url, { | ||
headers: this._headers() | ||
}).then(res => res.json()); | ||
headers: this._headers(), | ||
}).then((res) => res.json()); | ||
} | ||
@@ -143,4 +189,4 @@ | ||
body: JSON.stringify(body), | ||
headers: this._headers() | ||
}).then(res => res.json()); | ||
headers: this._headers(), | ||
}).then((res) => res.json()); | ||
} | ||
@@ -153,3 +199,3 @@ | ||
body: JSON.stringify(body), | ||
headers: this._headers() | ||
headers: this._headers(), | ||
}); | ||
@@ -161,4 +207,4 @@ } | ||
"Content-Type": "application/json", | ||
"Authorization": `Basic ${this.token}`, | ||
"User-Agent": "Oso Cloud (nodejs)" | ||
Authorization: `Basic ${this.token}`, | ||
"User-Agent": "Oso Cloud (nodejs)", | ||
}; | ||
@@ -165,0 +211,0 @@ } |
@@ -5,4 +5,3 @@ // To run the tests you must first start the service locally in test mode. | ||
const { Oso } = require("./client.js"); | ||
const assert = require("assert"); | ||
const { Oso } = require("./client"); | ||
@@ -21,62 +20,188 @@ class User { | ||
(async () => { | ||
try { | ||
const oso = new Oso( | ||
"http://localhost:8080", | ||
"dF8wMTIzNDU2Nzg5Om9zb190ZXN0X3Rva2Vu" | ||
); | ||
const user1 = new User(1); | ||
const repo2 = new Repo(2); | ||
const repo3 = new Repo(3); | ||
const oso = new Oso( | ||
"http://localhost:8080", | ||
"dF8wMTIzNDU2Nzg5Om9zb190ZXN0X3Rva2Vu" | ||
); | ||
await oso.policy(` | ||
actor User { | ||
} | ||
const policyDefault = ` | ||
actor User { | ||
} | ||
resource Repo { | ||
roles = ["member"]; | ||
permissions = ["read"]; | ||
relations = { parent: Repo }; | ||
"read" if "member"; | ||
} | ||
`); | ||
resource Repo { | ||
roles = ["member"]; | ||
permissions = ["read"]; | ||
relations = { parent: Repo }; | ||
"read" if "member"; | ||
} | ||
`; | ||
const user1 = new User(1); | ||
const repo1 = new Repo(1); | ||
const repo2 = new Repo(2); | ||
const repo3 = new Repo(3); | ||
describe("test authorize", () => { | ||
beforeAll(async () => { | ||
await oso.policy(policyDefault); | ||
}); | ||
afterAll(async () => { | ||
await oso.delete("has_permission", user1, "read", repo3); | ||
}); | ||
test("denied", async () => { | ||
const authorize = await oso.authorize(user1, "read", repo2); | ||
assert.strictEqual(authorize, false); | ||
expect(authorize).toEqual(false); | ||
}); | ||
test("allowed", async () => { | ||
await oso.tell("has_permission", user1, "read", repo3); | ||
const authorize = await oso.authorize(user1, "read", repo3); | ||
expect(authorize).toEqual(true); | ||
}); | ||
}); | ||
describe("test list", () => { | ||
beforeAll(async () => { | ||
await oso.policy(policyDefault); | ||
}); | ||
test("empty", async () => { | ||
const list = await oso.list(user1, "read", Repo); | ||
assert(Array.isArray(list) && list.length === 0); | ||
expect(Array.isArray(list)).toBeTruthy(); | ||
expect(list.length).toEqual(0); | ||
}); | ||
}); | ||
await oso.tell("has_relation", repo2, "parent", repo3); | ||
await oso.delete("has_relation", repo2, "parent", repo3); | ||
describe("test actions", () => { | ||
const fact = ["has_role", user1, "member", repo1]; | ||
beforeAll(async () => { | ||
await oso.policy(policyDefault); | ||
await oso.tell(...fact); | ||
}); | ||
afterAll(async () => { | ||
await oso.delete(...fact); | ||
}); | ||
test("read", async () => { | ||
const list = await oso.actions(user1, repo1); | ||
expect(Array.isArray(list)).toBeTruthy(); | ||
expect(list.length).toEqual(1); | ||
expect(list[0]).toEqual("read"); | ||
}); | ||
test("empty", async () => { | ||
const list = await oso.actions(user1, repo2); | ||
expect(Array.isArray(list)).toBeTruthy(); | ||
expect(list.length).toEqual(0); | ||
}); | ||
}); | ||
describe("test get", () => { | ||
beforeAll(async () => { | ||
await oso.policy(policyDefault); | ||
}); | ||
afterEach(async () => { | ||
await oso.delete("has_role", user1, "member", repo2); | ||
}); | ||
test("has_role", async () => { | ||
await oso.tell("has_role", user1, "member", repo2); | ||
const roles = await oso.get("has_role", user1, "member", repo2); | ||
assert(Array.isArray(roles) && roles.length === 1); | ||
expect(Array.isArray(roles)).toBeTruthy(); | ||
expect(roles.length).toEqual(1); | ||
const role = roles[0]; | ||
assert(role.args[1].id === "member"); | ||
const authorize_again = await oso.authorize(user1, "read", repo2); | ||
assert.strictEqual(authorize_again, true); | ||
expect(role.args[1].id).toEqual("member"); | ||
}); | ||
test("wildcards", async () => { | ||
await oso.tell("has_role", user1, "member", repo2); | ||
let roles = await oso.get("has_role", null, null, repo2); | ||
expect(Array.isArray(roles)).toBeTruthy(); | ||
expect(roles.length).toEqual(1); | ||
roles = await oso.get("has_role", null, null, user1); | ||
expect(Array.isArray(roles)).toBeTruthy(); | ||
expect(roles.length).toEqual(0); | ||
}); | ||
}); | ||
describe("test bulk facts", () => { | ||
const moreFacts = [ | ||
["has_role", user1, "member", repo2], | ||
["has_relation", repo2, "parent", repo3], | ||
]; | ||
beforeAll(async () => { | ||
await oso.policy(policyDefault); | ||
}); | ||
afterAll(async () => { | ||
await oso.bulkDelete(moreFacts); | ||
}); | ||
test("tell", async () => { | ||
await oso.bulkTell(moreFacts); | ||
const bulkRoles = await oso.get("has_role", user1, "member", repo2); | ||
expect(Array.isArray(bulkRoles)).toBeTruthy(); | ||
expect(bulkRoles.length).toEqual(1); | ||
const bulkRelations = await oso.get("has_relation", repo2, "parent", repo3); | ||
expect(Array.isArray(bulkRelations)).toBeTruthy(); | ||
expect(bulkRelations.length).toEqual(1); | ||
}); | ||
test("delete", async () => { | ||
await oso.bulkDelete(moreFacts); | ||
const bulkDeleteRoles = await oso.get("has_role", user1, "member", repo2); | ||
expect(Array.isArray(bulkDeleteRoles)).toBeTruthy(); | ||
expect(bulkDeleteRoles.length).toEqual(0); | ||
const bulkDeleteRelations = await oso.get( | ||
"has_relation", | ||
repo2, | ||
"parent", | ||
repo3 | ||
); | ||
expect(Array.isArray(bulkDeleteRelations)).toBeTruthy(); | ||
expect(bulkDeleteRelations.length).toEqual(0); | ||
}); | ||
}); | ||
describe("test authorize-resources", () => { | ||
beforeAll(async () => { | ||
await oso.policy(policyDefault); | ||
await oso.tell("has_role", user1, "member", repo1); | ||
await oso.tell("has_role", user1, "member", repo2); | ||
}); | ||
afterAll(async () => { | ||
await oso.delete("has_role", user1, "member", repo1); | ||
await oso.delete("has_role", user1, "member", repo2); | ||
}); | ||
const more_facts = [ | ||
["has_role", user1, "member", repo2], | ||
["has_relation", repo2, "parent", repo3] | ||
]; | ||
await oso.bulkTell(more_facts); | ||
const bulk_roles = await oso.get("has_role", user1, "member", repo2); | ||
assert(Array.isArray(bulk_roles) && bulk_roles.length === 1); | ||
const bulk_relations = await oso.get("has_relation", repo2, "parent", repo3); | ||
assert(Array.isArray(bulk_relations) && bulk_relations.length === 1); | ||
test("empty", async () => { | ||
let res = await oso.authorize_resources(user1, "read", []); | ||
expect(Array.isArray(res)).toBeTruthy(); | ||
expect(res.length).toEqual(0); | ||
res = await oso.authorize_resources(user1, "read", undefined); | ||
expect(Array.isArray(res)).toBeTruthy(); | ||
expect(res.length).toEqual(0); | ||
}); | ||
await oso.bulkDelete(more_facts); | ||
const bulk_delete_roles = await oso.get("has_role", user1, "member", repo2); | ||
assert(Array.isArray(bulk_delete_roles) && bulk_delete_roles.length === 0); | ||
const bulk_delete_relations = await oso.get("has_relation", repo2, "parent", repo3); | ||
assert(Array.isArray(bulk_delete_relations) && bulk_delete_relations.length === 0); | ||
} catch (e) { | ||
console.error(e); | ||
process.exitCode = 1; | ||
} | ||
})(); | ||
test("match all", async () => { | ||
const res = await oso.authorize_resources(user1, "read", [repo1, repo2]); | ||
expect(new Set(res)).toEqual(new Set([repo1, repo2])); | ||
}); | ||
test("match some", async () => { | ||
const res = await oso.authorize_resources(user1, "read", [repo1, repo3]); | ||
expect(new Set(res)).toEqual(new Set([repo1])); | ||
}); | ||
test("match none", async () => { | ||
const res = await oso.authorize_resources(user1, "read", [repo3]); | ||
expect(new Set(res)).toEqual(new Set([])); | ||
}); | ||
}); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
11597
5
348
8
4