Edits history of script submission #22721 for ' New Issues (wiz)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //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