//native
import * as wmill from "windmill-client"
/**
* New Issues
* Emits Wiz issues created since the last run. The first run records a watermark and returns nothing; subsequent runs return newly created issues (oldest first).
*/
export async function main(
auth: RT.Wiz,
severity:
| ("INFORMATIONAL" | "LOW" | "MEDIUM" | "HIGH" | "CRITICAL")[]
| undefined
) {
const tokenResponse = await fetch(
auth.auth_url || "https://auth.app.wiz.io/oauth/token",
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
audience: auth.audience || "wiz-api",
client_id: auth.client_id,
client_secret: auth.client_secret,
}),
}
)
if (!tokenResponse.ok) {
throw new Error(`${tokenResponse.status} ${await tokenResponse.text()}`)
}
const { access_token } = (await tokenResponse.json()) as {
access_token: string
}
const lastChecked: string | undefined = await wmill.getState()
// First run: record the watermark and skip the backlog.
if (!lastChecked) {
await wmill.setState(new Date().toISOString())
return []
}
const filterBy: { [key: string]: any } = { createdAt: { after: lastChecked } }
if (severity && severity.length > 0) filterBy.severity = severity
const query = `
query NewIssues($first: Int, $after: String, $filterBy: IssueFilters) {
issues: issuesV2(first: $first, after: $after, filterBy: $filterBy) {
pageInfo { hasNextPage endCursor }
nodes {
id
type
severity
status
createdAt
sourceRule {
__typename
... on Control { id name }
... on CloudConfigurationRule { id name }
... on CloudEventRule { id name }
}
entitySnapshot { id name type nativeType cloudPlatform region subscriptionName }
projects { id name }
}
}
}`
const newIssues: any[] = []
let after: string | null = null
// Cap total pages so a large backlog can't run forever.
for (let page = 0; page < 20; page++) {
const response = await fetch(auth.api_endpoint, {
method: "POST",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
query,
variables: { first: 100, after, filterBy },
}),
})
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const result = (await response.json()) as { data?: any; errors?: any }
if (result.errors) {
throw new Error(JSON.stringify(result.errors))
}
const conn = result.data.issues
newIssues.push(...conn.nodes)
if (!conn.pageInfo.hasNextPage) break
after = conn.pageInfo.endCursor
}
// Order is not guaranteed, so derive the new watermark from the newest
// createdAt seen and sort the output oldest-first ourselves.
if (newIssues.length > 0) {
const newest = newIssues.reduce(
(max, i) => (i.createdAt > max ? i.createdAt : max),
newIssues[0].createdAt
)
await wmill.setState(newest)
newIssues.sort((a, b) => (a.createdAt < b.createdAt ? -1 : 1))
}
return newIssues
}
Submitted by hugo989 5 days ago