diff --git a/docs/sources/github/example-api-responses/original/org_audit_log.json b/docs/sources/github/example-api-responses/original/org_audit_log.json index bd3c9f755..a2d90ed9c 100644 --- a/docs/sources/github/example-api-responses/original/org_audit_log.json +++ b/docs/sources/github/example-api-responses/original/org_audit_log.json @@ -63,5 +63,30 @@ "user": "octocat", "user_agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0", "user_id": 13968776 + }, + { + "repo": [ + "some-org/test" + ], + "repo_id": [ + 12324 + ], + "org": "some-org", + "org_id": 870, + "action": "migration.destroy_file", + "@timestamp": 1737730851061, + "created_at": 1737730851061, + "operation_type": "remove", + "data": { + "job": "MigrationDestroyFileJob", + "active_job_id": "some-job-id", + "aqueduct_job_id": "some-aqueduct-job-id", + "catalog_service": "github/unknown", + "migration_id": 2, + "public_repo": true, + "started_by": "octocat", + "started_by_id": 42, + "category_type": "Resource Management" + } } -] \ No newline at end of file +] diff --git a/docs/sources/github/example-api-responses/sanitized/org_audit_log.json b/docs/sources/github/example-api-responses/sanitized/org_audit_log.json index 9d225528f..18d7afa37 100644 --- a/docs/sources/github/example-api-responses/sanitized/org_audit_log.json +++ b/docs/sources/github/example-api-responses/sanitized/org_audit_log.json @@ -12,7 +12,7 @@ "repository":"some-org/test", "repository_public":false, "user":"null", - "user_id":0 + "user_id":"{\"hash\":\"uXY-rAXeOzg_TOxA3id5pRgzfCc7sMGRAnsZJK0Ds0U\"}" }, { "@timestamp":1688668100244, @@ -27,7 +27,7 @@ "repository":"some-org/test", "repository_public":false, "user":"null", - "user_id":0 + "user_id":"{\"hash\":\"uXY-rAXeOzg_TOxA3id5pRgzfCc7sMGRAnsZJK0Ds0U\"}" }, { "@timestamp":1688667848231, @@ -48,6 +48,26 @@ "repo":"some-org/test", "repository":"some-org/test", "user":"{\"hash\":\"IAUEqSLLtP3EjjkzslH-S1ULJZRLQnH9hT54jiI1gbM\"}", - "user_id":13968776 + "user_id":"{\"hash\":\"S3Nh4slc2XnLp5Qy1CD-pQew9-j0cePbX3U7-DE56Co\"}" + }, + { + "repo":[ + "some-org/test" + ], + "repo_id":[ + 12324 + ], + "org":"some-org", + "org_id":870, + "action":"migration.destroy_file", + "@timestamp":1737730851061, + "created_at":1737730851061, + "operation_type":"remove", + "data":{ + "public_repo":true, + "started_by":"{\"hash\":\"IAUEqSLLtP3EjjkzslH-S1ULJZRLQnH9hT54jiI1gbM\"}", + "started_by_id":42, + "category_type":"Resource Management" + } } ] diff --git a/docs/sources/github/github-enterprise-server.yaml b/docs/sources/github/github-enterprise-server.yaml index 8c381a266..a552bf9a7 100644 --- a/docs/sources/github/github-enterprise-server.yaml +++ b/docs/sources/github/github-enterprise-server.yaml @@ -261,11 +261,17 @@ endpoints: - "$..transport_protocol_name" - "$..pull_request_title" - "$..user_agent" + - "$..job" + - "$..active_job_id" + - "$..aqueduct_job_id" + - "$..catalog_service" + - "$..migration_id" - ! jsonPaths: - "$..actor" - "$..user" - - "$..userId" + - "$..user_id" + - "$..started_by" encoding: "JSON" - pathTemplate: "/api/{enterpriseServerVersion}/organizations/{installationId}/audit-log" allowedQueryParams: @@ -286,11 +292,17 @@ endpoints: - "$..transport_protocol_name" - "$..pull_request_title" - "$..user_agent" + - "$..job" + - "$..active_job_id" + - "$..aqueduct_job_id" + - "$..catalog_service" + - "$..migration_id" - ! jsonPaths: - "$..actor" - "$..user" - - "$..userId" + - "$..user_id" + - "$..started_by" encoding: "JSON" - pathTemplate: "/api/{enterpriseServerVersion}/orgs/{org}/repos" allowedQueryParams: @@ -847,4 +859,4 @@ endpoints: jsonPaths: - "$..assignees[*].login" includeReversible: true - encoding: "URL_SAFE_TOKEN" \ No newline at end of file + encoding: "URL_SAFE_TOKEN" diff --git a/docs/sources/github/github.yaml b/docs/sources/github/github.yaml index 2db863ff4..0e995dc06 100644 --- a/docs/sources/github/github.yaml +++ b/docs/sources/github/github.yaml @@ -261,11 +261,17 @@ endpoints: - "$..transport_protocol_name" - "$..pull_request_title" - "$..user_agent" + - "$..job" + - "$..active_job_id" + - "$..aqueduct_job_id" + - "$..catalog_service" + - "$..migration_id" - ! jsonPaths: - "$..actor" - "$..user" - - "$..userId" + - "$..user_id" + - "$..started_by" encoding: "JSON" - pathTemplate: "/organizations/{installationId}/audit-log" allowedQueryParams: @@ -286,11 +292,17 @@ endpoints: - "$..transport_protocol_name" - "$..pull_request_title" - "$..user_agent" + - "$..job" + - "$..active_job_id" + - "$..aqueduct_job_id" + - "$..catalog_service" + - "$..migration_id" - ! jsonPaths: - "$..actor" - "$..user" - - "$..userId" + - "$..user_id" + - "$..started_by" encoding: "JSON" - pathTemplate: "/orgs/{org}/repos" allowedQueryParams: @@ -847,4 +859,4 @@ endpoints: jsonPaths: - "$..assignees[*].login" includeReversible: true - encoding: "URL_SAFE_TOKEN" \ No newline at end of file + encoding: "URL_SAFE_TOKEN" diff --git a/java/core/src/main/java/co/worklytics/psoxy/rules/github/PrebuiltSanitizerRules.java b/java/core/src/main/java/co/worklytics/psoxy/rules/github/PrebuiltSanitizerRules.java index b6f0a0cc5..a8329a4fb 100644 --- a/java/core/src/main/java/co/worklytics/psoxy/rules/github/PrebuiltSanitizerRules.java +++ b/java/core/src/main/java/co/worklytics/psoxy/rules/github/PrebuiltSanitizerRules.java @@ -22,537 +22,549 @@ public class PrebuiltSanitizerRules { private static final List commonAllowedQueryParameters = Lists.newArrayList( - "per_page", - "page" + "per_page", + "page" ); private static final List userAllowedQueryParameters = Lists.newArrayList( - "since", - "per_page" + "since", + "per_page" ); private static final List commonDirectionAllowedQueryParameters = Lists.newArrayList( - "sort", - "direction" + "sort", + "direction" ); private static final List orgMembersAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - Lists.newArrayList("filter", - "role").stream()) - .collect(Collectors.toList()); + Lists.newArrayList("filter", + "role").stream()) + .collect(Collectors.toList()); private static final List orgAuditLogAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - Lists.newArrayList("phrase", - "include", - "after", - "before", - "order").stream()) - .collect(Collectors.toList()); + Lists.newArrayList("phrase", + "include", + "after", + "before", + "order").stream()) + .collect(Collectors.toList()); private static final List issuesAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - commonDirectionAllowedQueryParameters.stream(), - Lists.newArrayList("milestone", - "state", - "labels", - "since").stream()) - .collect(Collectors.toList()); + commonDirectionAllowedQueryParameters.stream(), + Lists.newArrayList("milestone", + "state", + "labels", + "since").stream()) + .collect(Collectors.toList()); private static final List issueCommentsQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - Lists.newArrayList("since").stream()) - .collect(Collectors.toList()); + Lists.newArrayList("since").stream()) + .collect(Collectors.toList()); private static final List repoListAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - commonDirectionAllowedQueryParameters.stream(), - Lists.newArrayList("type").stream()) - .collect(Collectors.toList()); + commonDirectionAllowedQueryParameters.stream(), + Lists.newArrayList("type").stream()) + .collect(Collectors.toList()); private static final List repoBranchesAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - Lists.newArrayList("protected").stream()) - .collect(Collectors.toList()); + Lists.newArrayList("protected").stream()) + .collect(Collectors.toList()); private static final List pullsAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - commonDirectionAllowedQueryParameters.stream(), - Lists.newArrayList("state", - "head", - "base").stream()) - .collect(Collectors.toList()); + commonDirectionAllowedQueryParameters.stream(), + Lists.newArrayList("state", + "head", + "base").stream()) + .collect(Collectors.toList()); private static final List pullsCommentsQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - commonDirectionAllowedQueryParameters.stream(), - Lists.newArrayList("since").stream()) - .collect(Collectors.toList()); + commonDirectionAllowedQueryParameters.stream(), + Lists.newArrayList("since").stream()) + .collect(Collectors.toList()); private static final List commitsAllowedQueryParameters = Streams.concat(commonAllowedQueryParameters.stream(), - Lists.newArrayList("sha", - "path", - "since", - "until").stream()) - .collect(Collectors.toList()); + Lists.newArrayList("sha", + "path", + "since", + "until").stream()) + .collect(Collectors.toList()); static final Endpoint ORG_MEMBERS = Endpoint.builder() - .pathTemplate("/orgs/{org}/members") - .allowedQueryParams(orgMembersAllowedQueryParameters) - .transforms(generateUserTransformations(".")) - .build(); + .pathTemplate("/orgs/{org}/members") + .allowedQueryParams(orgMembersAllowedQueryParameters) + .transforms(generateUserTransformations(".")) + .build(); // https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#list-users static final Endpoint USERS = Endpoint.builder() - .pathTemplate("/users/{username}") - .pathParameterSchemas(ImmutableMap.of("username", ParameterSchema.reversiblePseudonym())) - .allowedQueryParams(userAllowedQueryParameters) - .transforms(generateUserTransformations(".")) - .build(); + .pathTemplate("/users/{username}") + .pathParameterSchemas(ImmutableMap.of("username", ParameterSchema.reversiblePseudonym())) + .allowedQueryParams(userAllowedQueryParameters) + .transforms(generateUserTransformations(".")) + .build(); static final Endpoint GRAPHQL_FOR_USERS = Endpoint.builder() - .pathTemplate("/graphql") - .transform(Transform.Redact.builder() - .jsonPath("$..ssoUrl") - .build()) - .transform(Transform.Pseudonymize.builder() - .jsonPath("$..nameId") - .jsonPath("$..email") - .jsonPath("$..emails[*].value") - .jsonPath("$..guid") - .jsonPath("$..organizationVerifiedDomainEmails[*]") - .build()) - .transform(Transform.Pseudonymize.builder() - .includeReversible(true) - .encoding(PseudonymEncoder.Implementations.URL_SAFE_TOKEN) - .jsonPath("$..login") - .build()) - .responseSchema(jsonSchemaForUserQueryResult()) - .build(); + .pathTemplate("/graphql") + .transform(Transform.Redact.builder() + .jsonPath("$..ssoUrl") + .build()) + .transform(Transform.Pseudonymize.builder() + .jsonPath("$..nameId") + .jsonPath("$..email") + .jsonPath("$..emails[*].value") + .jsonPath("$..guid") + .jsonPath("$..organizationVerifiedDomainEmails[*]") + .build()) + .transform(Transform.Pseudonymize.builder() + .includeReversible(true) + .encoding(PseudonymEncoder.Implementations.URL_SAFE_TOKEN) + .jsonPath("$..login") + .build()) + .responseSchema(jsonSchemaForUserQueryResult()) + .build(); static final Endpoint ORG_TEAMS = Endpoint.builder() - .pathTemplate("/orgs/{org}/teams") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..description") - .build()) - .build(); + .pathTemplate("/orgs/{org}/teams") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..description") + .build()) + .build(); static final Endpoint ORG_AUDIT_LOG = Endpoint.builder() - .pathTemplate("/orgs/{org}/audit-log") - .allowedQueryParams(orgAuditLogAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..hashed_token") - .jsonPath("$..business") - .jsonPath("$..business_id") - .jsonPath("$..transport_protocol") - .jsonPath("$..transport_protocol_name") - .jsonPath("$..pull_request_title") - .jsonPath("$..user_agent") - .build()) - .transform(Transform.Pseudonymize.builder() - .jsonPath("$..actor") - .jsonPath("$..user") - .jsonPath("$..userId") - .build()) - .build(); + .pathTemplate("/orgs/{org}/audit-log") + .allowedQueryParams(orgAuditLogAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..hashed_token") + .jsonPath("$..business") + .jsonPath("$..business_id") + .jsonPath("$..transport_protocol") + .jsonPath("$..transport_protocol_name") + .jsonPath("$..pull_request_title") + .jsonPath("$..user_agent") + .jsonPath("$..job") + .jsonPath("$..active_job_id") + .jsonPath("$..aqueduct_job_id") + .jsonPath("$..catalog_service") + .jsonPath("$..migration_id") + .build()) + .transform(Transform.Pseudonymize.builder() + .jsonPath("$..actor") + .jsonPath("$..user") + .jsonPath("$..user_id") + .jsonPath("$..started_by") + .build()) + .build(); static final Endpoint ORG_AUDIT_LOG_WITH_INSTALLATION_ID = Endpoint.builder() - .pathTemplate("/organizations/{installationId}/audit-log") - .allowedQueryParams(orgAuditLogAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..hashed_token") - .jsonPath("$..business") - .jsonPath("$..business_id") - .jsonPath("$..transport_protocol") - .jsonPath("$..transport_protocol_name") - .jsonPath("$..pull_request_title") - .jsonPath("$..user_agent") - .build()) - .transform(Transform.Pseudonymize.builder() - .jsonPath("$..actor") - .jsonPath("$..user") - .jsonPath("$..userId") - .build()) - .build(); + .pathTemplate("/organizations/{installationId}/audit-log") + .allowedQueryParams(orgAuditLogAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..hashed_token") + .jsonPath("$..business") + .jsonPath("$..business_id") + .jsonPath("$..transport_protocol") + .jsonPath("$..transport_protocol_name") + .jsonPath("$..pull_request_title") + .jsonPath("$..user_agent") + .jsonPath("$..job") + .jsonPath("$..active_job_id") + .jsonPath("$..aqueduct_job_id") + .jsonPath("$..catalog_service") + .jsonPath("$..migration_id") + .build()) + .transform(Transform.Pseudonymize.builder() + .jsonPath("$..actor") + .jsonPath("$..user") + .jsonPath("$..user_id") + .jsonPath("$..started_by") + .build()) + .build(); static final Endpoint ORG_TEAM_MEMBERS = Endpoint.builder() - .pathTemplate("/orgs/{org}/teams/{teamSlug}/members") - .allowedQueryParams(commonAllowedQueryParameters) - .transforms(generateUserTransformations(".")) - .build(); + .pathTemplate("/orgs/{org}/teams/{teamSlug}/members") + .allowedQueryParams(commonAllowedQueryParameters) + .transforms(generateUserTransformations(".")) + .build(); static final Endpoint REPO_COMMIT = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/commits/{ref}") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..message") - .jsonPath("$..files") - .jsonPath("$..signature") - .jsonPath("$..payload") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList("author", "committer"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/commits/{ref}") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..message") + .jsonPath("$..files") + .jsonPath("$..signature") + .jsonPath("$..payload") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList("author", "committer"))) + .build(); static final Endpoint ISSUES = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues") - .allowedQueryParams(issuesAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..title") - .jsonPath("$..body") - .jsonPath("$..description") - .jsonPath("$..name") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList( - // Owner can be a user or an organization user - "owner", - "user", - "assignee", - "creator", - "closed_by"))) - // Seems array plus other object in filtering is not matching the json path, so a different rule for this - .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues") + .allowedQueryParams(issuesAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..title") + .jsonPath("$..body") + .jsonPath("$..description") + .jsonPath("$..name") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList( + // Owner can be a user or an organization user + "owner", + "user", + "assignee", + "creator", + "closed_by"))) + // Seems array plus other object in filtering is not matching the json path, so a different rule for this + .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) + .build(); static final Endpoint ISSUE = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}") - .transform(Transform.Redact.builder() - .jsonPath("$..title") - .jsonPath("$..body") - .jsonPath("$..description") - .jsonPath("$..name") - .jsonPath("$..pem") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList("user", "assignee", "creator", "closed_by"))) - .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}") + .transform(Transform.Redact.builder() + .jsonPath("$..title") + .jsonPath("$..body") + .jsonPath("$..description") + .jsonPath("$..name") + .jsonPath("$..pem") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList("user", "assignee", "creator", "closed_by"))) + .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) + .build(); static final Endpoint ISSUE_COMMENTS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/comments") - .allowedQueryParams(issueCommentsQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..url") - .jsonPath("$..message") - .jsonPath("$..body") - .build()) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/comments") + .allowedQueryParams(issueCommentsQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..url") + .jsonPath("$..message") + .jsonPath("$..body") + .build()) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint ISSUE_EVENTS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/events") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..url") - .jsonPath("$..body") - .jsonPath("$..rename") - .jsonPath("$..name") - .jsonPath("$..message") - .jsonPath("$..files") - .jsonPath("$..signature") - .jsonPath("$..payload") - .jsonPath("$..dismissalMessage") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList( - // Owner can be a user or an organization user - "owner", - "user", - "actor", - "assignee", - "assigner", - "creator", - "closed_by", - "author", - "committer", - "requested_reviewer", - "review_requester"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/events") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..url") + .jsonPath("$..body") + .jsonPath("$..rename") + .jsonPath("$..name") + .jsonPath("$..message") + .jsonPath("$..files") + .jsonPath("$..signature") + .jsonPath("$..payload") + .jsonPath("$..dismissalMessage") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList( + // Owner can be a user or an organization user + "owner", + "user", + "actor", + "assignee", + "assigner", + "creator", + "closed_by", + "author", + "committer", + "requested_reviewer", + "review_requester"))) + .build(); static final Endpoint ISSUE_TIMELINE = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/timeline") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..url") - .jsonPath("$..body") - .jsonPath("$..rename") - .jsonPath("$..name") - .jsonPath("$..message") - .jsonPath("$..files") - .jsonPath("$..signature") - .jsonPath("$..payload") - .jsonPath("$..dismissalMessage") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList( - // Owner can be a user or an organization user - "owner", - "user", - "actor", - "assignee", - "assigner", - "creator", - "closed_by", - "author", - "committer", - "requested_reviewer", - "review_requester"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/timeline") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..url") + .jsonPath("$..body") + .jsonPath("$..rename") + .jsonPath("$..name") + .jsonPath("$..message") + .jsonPath("$..files") + .jsonPath("$..signature") + .jsonPath("$..payload") + .jsonPath("$..dismissalMessage") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList( + // Owner can be a user or an organization user + "owner", + "user", + "actor", + "assignee", + "assigner", + "creator", + "closed_by", + "author", + "committer", + "requested_reviewer", + "review_requester"))) + .build(); static final Endpoint PULL_REVIEWS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/reviews") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..body") - .jsonPath("$..html_url") - .jsonPath("$..pull_request_url") - .build()) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/reviews") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..body") + .jsonPath("$..html_url") + .jsonPath("$..pull_request_url") + .build()) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint PULLS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/pulls") - .allowedQueryParams(pullsAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..title") - .jsonPath("$..body") - .jsonPath("$..name") - .jsonPath("$..description") - .jsonPath("$..url") - .jsonPath("$..homepage") - .jsonPath("$..commit_title") - .jsonPath("$..commit_message") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList( - // Owner can be a user or an organization user - "owner", - "user", - "actor", - "assignee", - "creator", - "merged_by", - "closed_by", - "enabled_by"))) - .transforms(generateUserTransformations("..requested_reviewers[*]", Collections.emptyList())) - .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) - .build(); + .pathTemplate("/repos/{owner}/{repo}/pulls") + .allowedQueryParams(pullsAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..title") + .jsonPath("$..body") + .jsonPath("$..name") + .jsonPath("$..description") + .jsonPath("$..url") + .jsonPath("$..homepage") + .jsonPath("$..commit_title") + .jsonPath("$..commit_message") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList( + // Owner can be a user or an organization user + "owner", + "user", + "actor", + "assignee", + "creator", + "merged_by", + "closed_by", + "enabled_by"))) + .transforms(generateUserTransformations("..requested_reviewers[*]", Collections.emptyList())) + .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) + .build(); static final Endpoint PULL = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}") - .transform(Transform.Redact.builder() - .jsonPath("$..title") - .jsonPath("$..body") - .jsonPath("$..name") - .jsonPath("$..description") - .jsonPath("$..homepage") - .jsonPath("$..commit_title") - .jsonPath("$..commit_message") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList( - // Owner can be a user or an organization user - "owner", - "user", - "actor", - "assignee", - "creator", - "merged_by", - "closed_by", - "enabled_by"))) - .transforms(generateUserTransformations("..requested_reviewers[*]", Collections.emptyList())) - .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) - .build(); + .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}") + .transform(Transform.Redact.builder() + .jsonPath("$..title") + .jsonPath("$..body") + .jsonPath("$..name") + .jsonPath("$..description") + .jsonPath("$..homepage") + .jsonPath("$..commit_title") + .jsonPath("$..commit_message") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList( + // Owner can be a user or an organization user + "owner", + "user", + "actor", + "assignee", + "creator", + "merged_by", + "closed_by", + "enabled_by"))) + .transforms(generateUserTransformations("..requested_reviewers[*]", Collections.emptyList())) + .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) + .build(); static final Endpoint REPOSITORIES = Endpoint.builder() - .pathTemplate("/orgs/{org}/repos") - .allowedQueryParams(repoListAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..description") - .jsonPath("$..homepage") - .build()) - // Owner can be a user or an organization user - .transforms(generateUserTransformations("..", Collections.singletonList("owner"))) - .build(); + .pathTemplate("/orgs/{org}/repos") + .allowedQueryParams(repoListAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..description") + .jsonPath("$..homepage") + .build()) + // Owner can be a user or an organization user + .transforms(generateUserTransformations("..", Collections.singletonList("owner"))) + .build(); // https://docs.github.com/en/rest/commits/comments?apiVersion=2022-11-28#list-commit-comments static final Endpoint COMMIT_COMMENTS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/commits/{commitSha}/comments") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..message") - .jsonPath("$..files") - .jsonPath("$..signature") - .jsonPath("$..payload") - .jsonPath("$..path") - .jsonPath("$..body") - .jsonPath("$..position") - .jsonPath("$..line") - .build()) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/commits/{commitSha}/comments") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..message") + .jsonPath("$..files") + .jsonPath("$..signature") + .jsonPath("$..payload") + .jsonPath("$..path") + .jsonPath("$..body") + .jsonPath("$..position") + .jsonPath("$..line") + .build()) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint COMMIT_COMMENT_REACTIONS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/comments/{commentId}/reactions") - .allowedQueryParams(commonAllowedQueryParameters) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/comments/{commentId}/reactions") + .allowedQueryParams(commonAllowedQueryParameters) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint ISSUE_REACTIONS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/reactions") - .allowedQueryParams(commonAllowedQueryParameters) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues/{issueNumber}/reactions") + .allowedQueryParams(commonAllowedQueryParameters) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint ISSUE_COMMENT_REACTIONS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/issues/comments/{commentId}/reactions") - .allowedQueryParams(commonAllowedQueryParameters) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/issues/comments/{commentId}/reactions") + .allowedQueryParams(commonAllowedQueryParameters) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint REPO_EVENTS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/events") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..display_login") - .jsonPath("$..avatar_url") - .jsonPath("$..gravatar_id") - .jsonPath("$..html_url") - .jsonPath("$..name") - .jsonPath("$..url") - .jsonPath("$..message") - .jsonPath("$..description") - .jsonPath("$..body") - .jsonPath("$..title") - .build()) - .transform(Transform.Pseudonymize.builder() - .jsonPath("$..author.email") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList( - // Owner can be a user or an organization user - "owner", - "user", - "actor", - "assignee", - "requested_reviewers[*]", "creator", "merged_by", "closed_by"))) - .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) - .build(); + .pathTemplate("/repos/{owner}/{repo}/events") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..display_login") + .jsonPath("$..avatar_url") + .jsonPath("$..gravatar_id") + .jsonPath("$..html_url") + .jsonPath("$..name") + .jsonPath("$..url") + .jsonPath("$..message") + .jsonPath("$..description") + .jsonPath("$..body") + .jsonPath("$..title") + .build()) + .transform(Transform.Pseudonymize.builder() + .jsonPath("$..author.email") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList( + // Owner can be a user or an organization user + "owner", + "user", + "actor", + "assignee", + "requested_reviewers[*]", "creator", "merged_by", "closed_by"))) + .transforms(generateUserTransformations("..assignees[*]", Collections.emptyList())) + .build(); static final Endpoint REPO_COMMITS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/commits") - .allowedQueryParams(commitsAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..message") - .jsonPath("$..files") - .jsonPath("$..signature") - .jsonPath("$..payload") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList("author", "committer"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/commits") + .allowedQueryParams(commitsAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..message") + .jsonPath("$..files") + .jsonPath("$..signature") + .jsonPath("$..payload") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList("author", "committer"))) + .build(); static final Endpoint REPO_BRANCHES = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/branches") - .allowedQueryParams(repoBranchesAllowedQueryParameters) - .build(); + .pathTemplate("/repos/{owner}/{repo}/branches") + .allowedQueryParams(repoBranchesAllowedQueryParameters) + .build(); static final Endpoint PULL_COMMITS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/commits") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..name") - .jsonPath("$..message") - .jsonPath("$..files") - .jsonPath("$..signature") - .jsonPath("$..payload") - .build()) - .transforms(generateUserTransformations("..", Arrays.asList("author", "committer"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/commits") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..name") + .jsonPath("$..message") + .jsonPath("$..files") + .jsonPath("$..signature") + .jsonPath("$..payload") + .build()) + .transforms(generateUserTransformations("..", Arrays.asList("author", "committer"))) + .build(); static final Endpoint PULL_COMMENTS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/comments") - .allowedQueryParams(pullsCommentsQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..path") - .jsonPath("$..diff_hunk") - .jsonPath("$..body") - .build()) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/comments") + .allowedQueryParams(pullsCommentsQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..path") + .jsonPath("$..diff_hunk") + .jsonPath("$..body") + .build()) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); static final Endpoint PULL_REVIEW_COMMENTS = Endpoint.builder() - .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/reviews/{reviewId}/comments") - .allowedQueryParams(commonAllowedQueryParameters) - .transform(Transform.Redact.builder() - .jsonPath("$..path") - .jsonPath("$..diff_hunk") - .jsonPath("$..body") - .build()) - .transforms(generateUserTransformations("..", Collections.singletonList("user"))) - .build(); + .pathTemplate("/repos/{owner}/{repo}/pulls/{pullNumber}/reviews/{reviewId}/comments") + .allowedQueryParams(commonAllowedQueryParameters) + .transform(Transform.Redact.builder() + .jsonPath("$..path") + .jsonPath("$..diff_hunk") + .jsonPath("$..body") + .build()) + .transforms(generateUserTransformations("..", Collections.singletonList("user"))) + .build(); @VisibleForTesting static final RESTRules GITHUB = Rules2.builder() - .endpoint(ORG_MEMBERS) - .endpoint(USERS) - .endpoint(GRAPHQL_FOR_USERS) - .endpoint(ORG_TEAMS) - .endpoint(ORG_TEAM_MEMBERS) - .endpoint(ORG_AUDIT_LOG) - .endpoint(ORG_AUDIT_LOG_WITH_INSTALLATION_ID) - .endpoint(REPOSITORIES) - .endpoint(REPO_BRANCHES) - .endpoint(REPO_COMMITS) - .endpoint(REPO_COMMIT) - .endpoint(REPO_EVENTS) - .endpoint(COMMIT_COMMENTS) - .endpoint(COMMIT_COMMENT_REACTIONS) - .endpoint(ISSUE) - .endpoint(ISSUES) - .endpoint(ISSUE_COMMENTS) - .endpoint(ISSUE_EVENTS) - .endpoint(ISSUE_TIMELINE) - .endpoint(ISSUE_REACTIONS) - .endpoint(ISSUE_COMMENT_REACTIONS) - .endpoint(PULL_REVIEWS) - .endpoint(PULLS) - .endpoint(PULL_COMMENTS) - .endpoint(PULL_REVIEW_COMMENTS) - .endpoint(PULL_COMMITS) - .endpoint(PULL) - .build(); + .endpoint(ORG_MEMBERS) + .endpoint(USERS) + .endpoint(GRAPHQL_FOR_USERS) + .endpoint(ORG_TEAMS) + .endpoint(ORG_TEAM_MEMBERS) + .endpoint(ORG_AUDIT_LOG) + .endpoint(ORG_AUDIT_LOG_WITH_INSTALLATION_ID) + .endpoint(REPOSITORIES) + .endpoint(REPO_BRANCHES) + .endpoint(REPO_COMMITS) + .endpoint(REPO_COMMIT) + .endpoint(REPO_EVENTS) + .endpoint(COMMIT_COMMENTS) + .endpoint(COMMIT_COMMENT_REACTIONS) + .endpoint(ISSUE) + .endpoint(ISSUES) + .endpoint(ISSUE_COMMENTS) + .endpoint(ISSUE_EVENTS) + .endpoint(ISSUE_TIMELINE) + .endpoint(ISSUE_REACTIONS) + .endpoint(ISSUE_COMMENT_REACTIONS) + .endpoint(PULL_REVIEWS) + .endpoint(PULLS) + .endpoint(PULL_COMMENTS) + .endpoint(PULL_REVIEW_COMMENTS) + .endpoint(PULL_COMMITS) + .endpoint(PULL) + .build(); @VisibleForTesting static final RESTRules GITHUB_ENTERPRISE_SERVER = Rules2.builder() - // NOTE: Enterprise Server endpoints are with /api/v3/ prefix for all requests, - // except for GraphQL which is just /api/ - // Leaving {enterpriseServerVersion} in the path template open to support future versions without changing rules - .endpoint(ORG_MEMBERS.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/members")) - .endpoint(USERS.withPathTemplate("/api/{enterpriseServerVersion}/users/{username}")) - .endpoint(GRAPHQL_FOR_USERS.withPathTemplate("/api/graphql")) - .endpoint(ORG_TEAMS.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/teams")) - .endpoint(ORG_TEAM_MEMBERS.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/teams/{teamSlug}/members")) - .endpoint(ORG_AUDIT_LOG.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/audit-log")) - .endpoint(ORG_AUDIT_LOG_WITH_INSTALLATION_ID.withPathTemplate("/api/{enterpriseServerVersion}/organizations/{installationId}/audit-log")) - .endpoint(REPOSITORIES.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/repos")) - .endpoint(REPO_BRANCHES.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/branches")) - .endpoint(REPO_COMMITS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/commits")) - .endpoint(REPO_COMMIT.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/commits/{ref}")) - .endpoint(REPO_EVENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/events")) - .endpoint(COMMIT_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/commits/{commitSha}/comments")) - .endpoint(COMMIT_COMMENT_REACTIONS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/comments/{commentId}/reactions")) - .endpoint(ISSUE.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}")) - .endpoint(ISSUES.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues")) - .endpoint(ISSUE_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/comments")) - .endpoint(ISSUE_EVENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/events")) - .endpoint(ISSUE_TIMELINE.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/timeline")) - .endpoint(ISSUE_REACTIONS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/reactions")) - .endpoint(ISSUE_COMMENT_REACTIONS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/comments/{commentId}/reactions")) - .endpoint(PULL_REVIEWS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/reviews")) - .endpoint(PULLS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls")) - .endpoint(PULL_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/comments")) - .endpoint(PULL_REVIEW_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/reviews/{reviewId}/comments")) - .endpoint(PULL_COMMITS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/commits")) - .endpoint(PULL.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}")) - .build(); + // NOTE: Enterprise Server endpoints are with /api/v3/ prefix for all requests, + // except for GraphQL which is just /api/ + // Leaving {enterpriseServerVersion} in the path template open to support future versions without changing rules + .endpoint(ORG_MEMBERS.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/members")) + .endpoint(USERS.withPathTemplate("/api/{enterpriseServerVersion}/users/{username}")) + .endpoint(GRAPHQL_FOR_USERS.withPathTemplate("/api/graphql")) + .endpoint(ORG_TEAMS.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/teams")) + .endpoint(ORG_TEAM_MEMBERS.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/teams/{teamSlug}/members")) + .endpoint(ORG_AUDIT_LOG.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/audit-log")) + .endpoint(ORG_AUDIT_LOG_WITH_INSTALLATION_ID.withPathTemplate("/api/{enterpriseServerVersion}/organizations/{installationId}/audit-log")) + .endpoint(REPOSITORIES.withPathTemplate("/api/{enterpriseServerVersion}/orgs/{org}/repos")) + .endpoint(REPO_BRANCHES.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/branches")) + .endpoint(REPO_COMMITS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/commits")) + .endpoint(REPO_COMMIT.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/commits/{ref}")) + .endpoint(REPO_EVENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/events")) + .endpoint(COMMIT_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/commits/{commitSha}/comments")) + .endpoint(COMMIT_COMMENT_REACTIONS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/comments/{commentId}/reactions")) + .endpoint(ISSUE.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}")) + .endpoint(ISSUES.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues")) + .endpoint(ISSUE_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/comments")) + .endpoint(ISSUE_EVENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/events")) + .endpoint(ISSUE_TIMELINE.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/timeline")) + .endpoint(ISSUE_REACTIONS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/{issueNumber}/reactions")) + .endpoint(ISSUE_COMMENT_REACTIONS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/issues/comments/{commentId}/reactions")) + .endpoint(PULL_REVIEWS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/reviews")) + .endpoint(PULLS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls")) + .endpoint(PULL_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/comments")) + .endpoint(PULL_REVIEW_COMMENTS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/reviews/{reviewId}/comments")) + .endpoint(PULL_COMMITS.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}/commits")) + .endpoint(PULL.withPathTemplate("/api/{enterpriseServerVersion}/repos/{owner}/{repo}/pulls/{pullNumber}")) + .build(); public static final Map RULES_MAP = - ImmutableMap.builder() - .put("github", GITHUB) - .put("github-enterprise-server", GITHUB_ENTERPRISE_SERVER) - .build(); + ImmutableMap.builder() + .put("github", GITHUB) + .put("github-enterprise-server", GITHUB_ENTERPRISE_SERVER) + .build(); private static List generateUserTransformations(String prefix) { return generateUserTransformations(prefix, Collections.emptyList()); @@ -563,192 +575,192 @@ private static List generateUserTransformations(String prefix, List String.format("'%s'", i)) - .collect(Collectors.toSet()), ",")); + .map(i -> String.format("'%s'", i)) + .collect(Collectors.toSet()), ",")); } return Arrays.asList( - // Following expression works for subproperties: - // $..['user', 'owner', ... ]['avatar_url','gravatar_id',...] - // but one there is no property and it is on the root, it is not working: - // $..['avatar_url','gravatar_id',...] - // so to have that working, in root case they are expanded instead of put them as an array - prefix.equals(".") ? Transform.Redact.builder() - .jsonPath(String.format("$%s%s.avatar_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.gravatar_id", prefix, objectNames)) - .jsonPath(String.format("$%s%s.url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.html_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.followers_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.following_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.gists_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.starred_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.subscriptions_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.organizations_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.repos_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.events_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.received_events_url", prefix, objectNames)) - .jsonPath(String.format("$%s%s.name", prefix, objectNames)) - .jsonPath(String.format("$%s%s.company", prefix, objectNames)) - .jsonPath(String.format("$%s%s.location", prefix, objectNames)) - .jsonPath(String.format("$%s%s.bio", prefix, objectNames)) - .jsonPath(String.format("$%s%s.twitter_username", prefix, objectNames)) - .build() : - Transform.Redact.builder() - .jsonPath(String.format("$%s%s.['avatar_url'," + - "'gravatar_id'," + - "'url'," + - "'html_url'," + - "'followers_url'," + - "'following_url'," + - "'gists_url'," + - "'starred_url'," + - "'subscriptions_url'," + - "'organizations_url'," + - "'repos_url'," + - "'events_url'," + - "'received_events_url'," + - "'name'," + - "'company'," + - "'location'," + - "'bio'," + - "'twitter_username']", prefix, objectNames)) - .build(), - - prefix.equals(".") ? - Transform.Pseudonymize.builder() - .jsonPath(String.format("$%s%s.id", prefix, objectNames)) - .jsonPath(String.format("$%s%s.node_id", prefix, objectNames)) - .jsonPath(String.format("$%s%s.email", prefix, objectNames)) - .build() : - Transform.Pseudonymize.builder() - .jsonPath(String.format("$%s%s.['id','node_id','email']", prefix, objectNames)) - .build() - , + // Following expression works for subproperties: + // $..['user', 'owner', ... ]['avatar_url','gravatar_id',...] + // but one there is no property and it is on the root, it is not working: + // $..['avatar_url','gravatar_id',...] + // so to have that working, in root case they are expanded instead of put them as an array + prefix.equals(".") ? Transform.Redact.builder() + .jsonPath(String.format("$%s%s.avatar_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.gravatar_id", prefix, objectNames)) + .jsonPath(String.format("$%s%s.url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.html_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.followers_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.following_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.gists_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.starred_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.subscriptions_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.organizations_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.repos_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.events_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.received_events_url", prefix, objectNames)) + .jsonPath(String.format("$%s%s.name", prefix, objectNames)) + .jsonPath(String.format("$%s%s.company", prefix, objectNames)) + .jsonPath(String.format("$%s%s.location", prefix, objectNames)) + .jsonPath(String.format("$%s%s.bio", prefix, objectNames)) + .jsonPath(String.format("$%s%s.twitter_username", prefix, objectNames)) + .build() : + Transform.Redact.builder() + .jsonPath(String.format("$%s%s.['avatar_url'," + + "'gravatar_id'," + + "'url'," + + "'html_url'," + + "'followers_url'," + + "'following_url'," + + "'gists_url'," + + "'starred_url'," + + "'subscriptions_url'," + + "'organizations_url'," + + "'repos_url'," + + "'events_url'," + + "'received_events_url'," + + "'name'," + + "'company'," + + "'location'," + + "'bio'," + + "'twitter_username']", prefix, objectNames)) + .build(), + + prefix.equals(".") ? + Transform.Pseudonymize.builder() + .jsonPath(String.format("$%s%s.id", prefix, objectNames)) + .jsonPath(String.format("$%s%s.node_id", prefix, objectNames)) + .jsonPath(String.format("$%s%s.email", prefix, objectNames)) + .build() : Transform.Pseudonymize.builder() - .includeReversible(true) - .encoding(PseudonymEncoder.Implementations.URL_SAFE_TOKEN) - .jsonPath(String.format("$%s%s.login", prefix, objectNames)) - .build() + .jsonPath(String.format("$%s%s.['id','node_id','email']", prefix, objectNames)) + .build() + , + Transform.Pseudonymize.builder() + .includeReversible(true) + .encoding(PseudonymEncoder.Implementations.URL_SAFE_TOKEN) + .jsonPath(String.format("$%s%s.login", prefix, objectNames)) + .build() ); } private static JsonSchemaFilter jsonSchemaForUserQueryResult() { return JsonSchemaFilter.builder() - .type("object") - // Using LinkedHashMap to keep the order to support same - // YAML serialization result - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("data", JsonSchemaFilter.builder() + .type("object") + // Using LinkedHashMap to keep the order to support same + // YAML serialization result + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("data", JsonSchemaFilter.builder() + .type("object") + .properties(new LinkedHashMap() {{ + put("organization", JsonSchemaFilter.builder() .type("object") .properties(new LinkedHashMap() {{ - put("organization", JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ - put("samlIdentityProvider", jsonSchemaForOrganizationProperty("externalIdentities", jsonSchemaForSamlNode())); - put("membersWithRole", jsonSchemaForQueryResult(jsonSchemaForMemberNode())); - }}).build()); + put("samlIdentityProvider", jsonSchemaForOrganizationProperty("externalIdentities", jsonSchemaForSamlNode())); + put("membersWithRole", jsonSchemaForQueryResult(jsonSchemaForMemberNode())); }}).build()); - put("errors", jsonSchemaForErrors()); - }}).build(); + }}).build()); + put("errors", jsonSchemaForErrors()); + }}).build(); } private static JsonSchemaFilter jsonSchemaForOrganizationProperty(String propertyName, JsonSchemaFilter node) { return JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ - put("externalIdentities", jsonSchemaForQueryResult(node)); - }}).build(); + .type("object") + .properties(new LinkedHashMap() {{ + put("externalIdentities", jsonSchemaForQueryResult(node)); + }}).build(); } private static JsonSchemaFilter jsonSchemaForQueryResult(JsonSchemaFilter node) { return JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ - put("pageInfo", jsonSchemaForPageInfo()); - put("edges", jsonSchemaForEdge(node)); - }}).build(); + .type("object") + .properties(new LinkedHashMap() {{ + put("pageInfo", jsonSchemaForPageInfo()); + put("edges", jsonSchemaForEdge(node)); + }}).build(); } private static JsonSchemaFilter jsonSchemaForPageInfo() { return JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("hasNextPage", JsonSchemaFilter.builder().type("boolean").build()); - put("endCursor", JsonSchemaFilter.builder().type("string").build()); - }}) - .build(); + .type("object") + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("hasNextPage", JsonSchemaFilter.builder().type("boolean").build()); + put("endCursor", JsonSchemaFilter.builder().type("string").build()); + }}) + .build(); } private static JsonSchemaFilter jsonSchemaForEdge(JsonSchemaFilter node) { return JsonSchemaFilter.builder() - .type("array") - .items(JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("node", node); - }}) - .build()) - .build(); + .type("array") + .items(JsonSchemaFilter.builder() + .type("object") + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("node", node); + }}) + .build()) + .build(); } private static JsonSchemaFilter jsonSchemaForSamlNode() { return JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("guid", JsonSchemaFilter.builder().type("string").build()); - put("samlIdentity", JsonSchemaFilter.builder().type("object").properties(new LinkedHashMap() {{ - put("nameId", JsonSchemaFilter.builder().type("string").build()); - put("emails", JsonSchemaFilter.builder() - .type("array") - .items(JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("value", JsonSchemaFilter.builder().type("string").build()); - }}) - .build()) - .build()); - }}).build()); - put("user", JsonSchemaFilter.builder().type("object").properties(new LinkedHashMap() {{ - put("login", JsonSchemaFilter.builder().type("string").build()); - }}).build()); - }}) - .build(); + .type("object") + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("guid", JsonSchemaFilter.builder().type("string").build()); + put("samlIdentity", JsonSchemaFilter.builder().type("object").properties(new LinkedHashMap() {{ + put("nameId", JsonSchemaFilter.builder().type("string").build()); + put("emails", JsonSchemaFilter.builder() + .type("array") + .items(JsonSchemaFilter.builder() + .type("object") + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("value", JsonSchemaFilter.builder().type("string").build()); + }}) + .build()) + .build()); + }}).build()); + put("user", JsonSchemaFilter.builder().type("object").properties(new LinkedHashMap() {{ + put("login", JsonSchemaFilter.builder().type("string").build()); + }}).build()); + }}) + .build(); } private static JsonSchemaFilter jsonSchemaForMemberNode() { return JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("email", JsonSchemaFilter.builder().type("string").build()); - put("login", JsonSchemaFilter.builder().type("string").build()); - put("id", JsonSchemaFilter.builder().type("string").build()); - put("isSiteAdmin", JsonSchemaFilter.builder().type("boolean").build()); - put("organizationVerifiedDomainEmails", JsonSchemaFilter.builder() - .type("array") - .items(JsonSchemaFilter.builder().type("string").build()) - .build()); - }}) - .build(); + .type("object") + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("email", JsonSchemaFilter.builder().type("string").build()); + put("login", JsonSchemaFilter.builder().type("string").build()); + put("id", JsonSchemaFilter.builder().type("string").build()); + put("isSiteAdmin", JsonSchemaFilter.builder().type("boolean").build()); + put("organizationVerifiedDomainEmails", JsonSchemaFilter.builder() + .type("array") + .items(JsonSchemaFilter.builder().type("string").build()) + .build()); + }}) + .build(); } private static JsonSchemaFilter jsonSchemaForErrors() { return JsonSchemaFilter.builder() - .type("array") - .items(JsonSchemaFilter.builder() - .type("object") - .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility - put("type", JsonSchemaFilter.builder().type("string").build()); - put("path", JsonSchemaFilter.builder().type("array") - .items(JsonSchemaFilter.builder().type("string").build()).build()); - put("locations", JsonSchemaFilter.builder().type("array") - .items(JsonSchemaFilter.builder().type("object") - .properties(new LinkedHashMap() { - { - put("line", JsonSchemaFilter.builder().type("integer").build()); - put("column", JsonSchemaFilter.builder().type("integer").build()); - } - }).build()).build()); - put("message", JsonSchemaFilter.builder().type("string").build()); - }}).build()).build(); + .type("array") + .items(JsonSchemaFilter.builder() + .type("object") + .properties(new LinkedHashMap() {{ //req for java8-backwards compatibility + put("type", JsonSchemaFilter.builder().type("string").build()); + put("path", JsonSchemaFilter.builder().type("array") + .items(JsonSchemaFilter.builder().type("string").build()).build()); + put("locations", JsonSchemaFilter.builder().type("array") + .items(JsonSchemaFilter.builder().type("object") + .properties(new LinkedHashMap() { + { + put("line", JsonSchemaFilter.builder().type("integer").build()); + put("column", JsonSchemaFilter.builder().type("integer").build()); + } + }).build()).build()); + put("message", JsonSchemaFilter.builder().type("string").build()); + }}).build()).build(); } -} \ No newline at end of file +}