-
Notifications
You must be signed in to change notification settings - Fork 0
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
JQ filtering in client #20
Changes from 8 commits
a8a4424
994af98
25afe6d
c6717da
1e580f6
6b177c3
747a9f4
2a56aee
5e06237
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env sh | ||
. "$(dirname -- "$0")/_/husky.sh" | ||
|
||
yarn run lint-staged |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`json path filter returns only selected fields 1`] = ` | ||
{ | ||
"data": { | ||
"items": [ | ||
{ | ||
"metadata": { | ||
"name": "admin", | ||
}, | ||
}, | ||
{ | ||
"metadata": { | ||
"name": "aws-node", | ||
}, | ||
}, | ||
], | ||
"kind": "ClusterRoleList", | ||
}, | ||
"status": 200, | ||
} | ||
`; | ||
|
||
exports[`json path filter returns original input data on error 1`] = ` | ||
{ | ||
"data": { | ||
"apiVersion": "rbac.authorization.k8s.io/v1", | ||
"items": [ | ||
{ | ||
"metadata": { | ||
"managedFields": [ | ||
{ | ||
"manager": "clusterrole-aggregation-controller", | ||
"operation": "Apply", | ||
}, | ||
{ | ||
"manager": "kube-apiserver", | ||
"operation": "Update", | ||
}, | ||
], | ||
"name": "admin", | ||
"resourceVersion": "345", | ||
"uid": "4251609f-b3ca-4875-8ec6-76b40ab62748", | ||
}, | ||
}, | ||
{ | ||
"metadata": { | ||
"managedFields": [ | ||
{ | ||
"manager": "kubectl-client-side-apply", | ||
"operation": "Update", | ||
}, | ||
], | ||
"name": "aws-node", | ||
"resourceVersion": "273", | ||
"uid": "63a3bed8-a750-440d-bca9-b5f41c8786c2", | ||
}, | ||
}, | ||
], | ||
"kind": "ClusterRoleList", | ||
"metadata": { | ||
"resourceVersion": "4423772", | ||
}, | ||
}, | ||
"status": 200, | ||
"statusText": "OK", | ||
} | ||
`; | ||
|
||
exports[`json path filter returns original input data when no filter supplied 1`] = ` | ||
{ | ||
"data": { | ||
"apiVersion": "rbac.authorization.k8s.io/v1", | ||
"items": [ | ||
{ | ||
"metadata": { | ||
"managedFields": [ | ||
{ | ||
"manager": "clusterrole-aggregation-controller", | ||
"operation": "Apply", | ||
}, | ||
{ | ||
"manager": "kube-apiserver", | ||
"operation": "Update", | ||
}, | ||
], | ||
"name": "admin", | ||
"resourceVersion": "345", | ||
"uid": "4251609f-b3ca-4875-8ec6-76b40ab62748", | ||
}, | ||
}, | ||
{ | ||
"metadata": { | ||
"managedFields": [ | ||
{ | ||
"manager": "kubectl-client-side-apply", | ||
"operation": "Update", | ||
}, | ||
], | ||
"name": "aws-node", | ||
"resourceVersion": "273", | ||
"uid": "63a3bed8-a750-440d-bca9-b5f41c8786c2", | ||
}, | ||
}, | ||
], | ||
"kind": "ClusterRoleList", | ||
"metadata": { | ||
"resourceVersion": "4423772", | ||
}, | ||
}, | ||
"status": 200, | ||
"statusText": "OK", | ||
} | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { jpFilter as jqFilter } from "../filter"; | ||
|
||
const exampleResponse = { | ||
status: 200, | ||
statusText: "OK", | ||
data: { | ||
kind: "ClusterRoleList", | ||
apiVersion: "rbac.authorization.k8s.io/v1", | ||
metadata: { | ||
resourceVersion: "4423772", | ||
}, | ||
items: [ | ||
{ | ||
metadata: { | ||
name: "admin", | ||
uid: "4251609f-b3ca-4875-8ec6-76b40ab62748", | ||
resourceVersion: "345", | ||
managedFields: [ | ||
{ | ||
manager: "clusterrole-aggregation-controller", | ||
operation: "Apply", | ||
}, | ||
{ | ||
manager: "kube-apiserver", | ||
operation: "Update", | ||
}, | ||
], | ||
}, | ||
}, | ||
{ | ||
metadata: { | ||
name: "aws-node", | ||
uid: "63a3bed8-a750-440d-bca9-b5f41c8786c2", | ||
resourceVersion: "273", | ||
managedFields: [ | ||
{ | ||
manager: "kubectl-client-side-apply", | ||
operation: "Update", | ||
}, | ||
], | ||
}, | ||
}, | ||
], | ||
}, | ||
}; | ||
|
||
describe("json path filter", () => { | ||
it("returns only selected fields", async () => { | ||
const result = await jqFilter( | ||
exampleResponse, | ||
"{ status: .status, data: { kind: .data.kind, items: [.data.items[] | { metadata: { name: .metadata.name } }] } }" | ||
); | ||
|
||
expect(result).toMatchSnapshot(); | ||
}); | ||
|
||
describe("returns original input data", () => { | ||
it("on error", async () => { | ||
const result = await jqFilter(exampleResponse, "{ { }"); | ||
|
||
expect(result).toMatchSnapshot(); | ||
}); | ||
|
||
it("when no filter supplied", async () => { | ||
const result = await jqFilter(exampleResponse, undefined); | ||
|
||
expect(result).toMatchSnapshot(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,28 @@ | ||||||
import { isArray } from "lodash"; | ||||||
|
||||||
import { createLogger } from "../log"; | ||||||
|
||||||
const logger = createLogger({ name: "filter" }); | ||||||
|
||||||
// jq-node doesn't support `import` syntax | ||||||
const jq = require("node-jq"); | ||||||
|
||||||
export const jpFilter = async ( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume you meant
Suggested change
|
||||||
data: any, | ||||||
jqHeader: string | string[] | undefined | ||||||
): Promise<any> => { | ||||||
const query = isArray(jqHeader) ? jqHeader[0] : jqHeader; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't you want to run this multiple times if there are multiple headers?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean chain the header jq commands? The output of the first is the input of the second? |
||||||
if (!query) { | ||||||
return data; | ||||||
} | ||||||
try { | ||||||
// jq.run() returns a Promise | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I think this comment is unnecessary. The fact the line below passes eslint already means the function returns a promise. |
||||||
return await jq.run(query, data, { input: "json", output: "json" }); | ||||||
} catch (error: any) { | ||||||
logger.error( | ||||||
{ error, jpSelectQuery: query }, | ||||||
"Error running jq query, ignoring filters" | ||||||
); | ||||||
return data; | ||||||
} | ||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ export const createLogger = <T extends LoggerOptions>( | |
// Redact the authorization header that may contain a secret token | ||
redact: [ | ||
"response.config.headers.authorization", // Axios intercepted response object | ||
"response.request.headers.authorization", // Axios intercepted response object contains the request as well | ||
"request.headers.authorization", // Axios intercepted request object + forwarded request object (JSON RPC request) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you also want just |
||
], | ||
formatters: { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
importOrder: ["^(cli|testing)([/]|$)", "^[.][.]?([/]|$)"], | ||
importOrderSeparation: true, | ||
importOrderSortSpecifiers: true, | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,6 +2,8 @@ import { Request } from "express"; | |||||
import core from "express-serve-static-core"; | ||||||
import { IncomingHttpHeaders } from "node:http"; | ||||||
|
||||||
export const JQ_HEADER = "braekhus-jq-response-filter"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what motivated you not to add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not recommended anymore: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a jq program, not a filter, right? Were it a filter I presume your invocation would look more like Should this be
Suggested change
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Called it |
||||||
|
||||||
export type IncomingRequest = Request< | ||||||
core.ParamsDictionary, | ||||||
any, | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm I think rather our node config doesn't support
import
of this module. Can you explain the error you get here, and leave a TODO to fix our node config?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.