Writes a markdown table of audit log resources to a buffer
(doc []byte, auditableResourcesMap AuditableResourcesMap)
| 95 | |
| 96 | // Writes a markdown table of audit log resources to a buffer |
| 97 | func updateAuditDoc(doc []byte, auditableResourcesMap AuditableResourcesMap) ([]byte, error) { |
| 98 | // We must sort the resources to ensure table ordering |
| 99 | sortedResourceNames := maps.SortedKeys(auditableResourcesMap) |
| 100 | |
| 101 | i := bytes.Index(doc, generatorPrefix) |
| 102 | if i < 0 { |
| 103 | return nil, xerrors.New("generator prefix tag not found") |
| 104 | } |
| 105 | tableStartIndex := i + len(generatorPrefix) + 1 |
| 106 | |
| 107 | j := bytes.Index(doc[tableStartIndex:], generatorSuffix) |
| 108 | if j < 0 { |
| 109 | return nil, xerrors.New("generator suffix tag not found") |
| 110 | } |
| 111 | tableEndIndex := tableStartIndex + j |
| 112 | |
| 113 | var buffer bytes.Buffer |
| 114 | _, _ = buffer.Write(doc[:tableStartIndex]) |
| 115 | _ = buffer.WriteByte('\n') |
| 116 | |
| 117 | _, _ = buffer.WriteString("|<b>Resource<b>||\n") |
| 118 | _, _ = buffer.WriteString("|--|-----------------|\n") |
| 119 | |
| 120 | for _, resourceName := range sortedResourceNames { |
| 121 | readableResourceName := resourceName |
| 122 | // AuditableGroup is really a combination of Group and GroupMember resources |
| 123 | // but we use the label 'Group' in our docs to avoid confusion. |
| 124 | if resourceName == "AuditableGroup" { |
| 125 | readableResourceName = "Group" |
| 126 | } |
| 127 | |
| 128 | // Create a string of audit actions for each resource |
| 129 | var auditActions []string |
| 130 | for _, action := range audit.AuditActionMap[readableResourceName] { |
| 131 | auditActions = append(auditActions, string(action)) |
| 132 | } |
| 133 | auditActionsString := strings.Join(auditActions, ", ") |
| 134 | |
| 135 | _, _ = buffer.WriteString("|" + readableResourceName + "<br><i>" + auditActionsString + "</i>|<table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody>" + "|") |
| 136 | |
| 137 | // We must sort the field names to ensure sub-table ordering |
| 138 | sortedFieldNames := maps.SortedKeys(auditableResourcesMap[resourceName]) |
| 139 | |
| 140 | for _, fieldName := range sortedFieldNames { |
| 141 | isTracked := auditableResourcesMap[resourceName][fieldName] |
| 142 | _, _ = buffer.WriteString("<tr><td>" + fieldName + "</td><td>" + strconv.FormatBool(isTracked) + "</td></tr>") |
| 143 | } |
| 144 | |
| 145 | _, _ = buffer.WriteString("</tbody></table>\n") |
| 146 | } |
| 147 | |
| 148 | _, _ = buffer.WriteString("\n") |
| 149 | _, _ = buffer.Write(doc[tableEndIndex:]) |
| 150 | return buffer.Bytes(), nil |
| 151 | } |
| 152 | |
| 153 | func writeAuditDoc(doc []byte) error { |
| 154 | return atomicwrite.File(auditDocFile, doc) |
no test coverage detected