@atproto/ozone 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/package.json +25 -21
- package/bin/migration-create.ts +0 -38
- package/jest.config.cjs +0 -22
- package/src/api/chat/getActorMetadata.ts +0 -23
- package/src/api/chat/getConvo.ts +0 -23
- package/src/api/chat/getConvoMembers.ts +0 -23
- package/src/api/chat/getConvos.ts +0 -23
- package/src/api/chat/getMessageContext.ts +0 -42
- package/src/api/chat/index.ts +0 -16
- package/src/api/communication/createTemplate.ts +0 -51
- package/src/api/communication/deleteTemplate.ts +0 -23
- package/src/api/communication/listTemplates.ts +0 -31
- package/src/api/communication/updateTemplate.ts +0 -51
- package/src/api/health.ts +0 -27
- package/src/api/index.ts +0 -146
- package/src/api/label/fetchLabels.ts +0 -32
- package/src/api/label/queryLabels.ts +0 -57
- package/src/api/label/subscribeLabels.ts +0 -25
- package/src/api/moderation/cancelScheduledActions.ts +0 -72
- package/src/api/moderation/emitEvent.ts +0 -475
- package/src/api/moderation/getAccountTimeline.ts +0 -160
- package/src/api/moderation/getEvent.ts +0 -19
- package/src/api/moderation/getRecord.ts +0 -40
- package/src/api/moderation/getRecords.ts +0 -50
- package/src/api/moderation/getRepo.ts +0 -34
- package/src/api/moderation/getReporterStats.ts +0 -18
- package/src/api/moderation/getRepos.ts +0 -41
- package/src/api/moderation/getSubjects.ts +0 -101
- package/src/api/moderation/listScheduledActions.ts +0 -45
- package/src/api/moderation/queryEvents.ts +0 -72
- package/src/api/moderation/queryStatuses.ts +0 -23
- package/src/api/moderation/scheduleAction.ts +0 -129
- package/src/api/moderation/searchRepos.ts +0 -46
- package/src/api/moderation/util.ts +0 -96
- package/src/api/proxied.ts +0 -327
- package/src/api/queue/assignModerator.ts +0 -31
- package/src/api/queue/createQueue.ts +0 -62
- package/src/api/queue/deleteQueue.ts +0 -56
- package/src/api/queue/getAssignments.ts +0 -19
- package/src/api/queue/listQueues.ts +0 -39
- package/src/api/queue/routeReports.ts +0 -44
- package/src/api/queue/unassignModerator.ts +0 -26
- package/src/api/queue/updateQueue.ts +0 -54
- package/src/api/report/assignModerator.ts +0 -36
- package/src/api/report/createActivity.ts +0 -57
- package/src/api/report/createReport.ts +0 -93
- package/src/api/report/getAssignments.ts +0 -20
- package/src/api/report/getHistoricalStats.ts +0 -41
- package/src/api/report/getLatestReport.ts +0 -44
- package/src/api/report/getLiveStats.ts +0 -26
- package/src/api/report/getReport.ts +0 -55
- package/src/api/report/listActivities.ts +0 -37
- package/src/api/report/queryActivities.ts +0 -64
- package/src/api/report/queryReports.ts +0 -44
- package/src/api/report/reassignQueue.ts +0 -68
- package/src/api/report/refreshStats.ts +0 -27
- package/src/api/report/unassignModerator.ts +0 -21
- package/src/api/safelink/addRule.ts +0 -48
- package/src/api/safelink/queryEvents.ts +0 -32
- package/src/api/safelink/queryRules.ts +0 -58
- package/src/api/safelink/removeRule.ts +0 -42
- package/src/api/safelink/updateRule.ts +0 -48
- package/src/api/server/getConfig.ts +0 -35
- package/src/api/set/addValues.ts +0 -28
- package/src/api/set/deleteSet.ts +0 -34
- package/src/api/set/deleteValues.ts +0 -31
- package/src/api/set/getValues.ts +0 -42
- package/src/api/set/querySets.ts +0 -36
- package/src/api/set/upsertSet.ts +0 -38
- package/src/api/setting/listOptions.ts +0 -44
- package/src/api/setting/removeOptions.ts +0 -64
- package/src/api/setting/upsertOption.ts +0 -156
- package/src/api/team/addMember.ts +0 -51
- package/src/api/team/deleteMember.ts +0 -29
- package/src/api/team/listMembers.ts +0 -20
- package/src/api/team/updateMember.ts +0 -47
- package/src/api/util.ts +0 -265
- package/src/api/verification/grantVerifications.ts +0 -90
- package/src/api/verification/listVerifications.ts +0 -44
- package/src/api/verification/revokeVerifications.ts +0 -43
- package/src/api/well-known.ts +0 -46
- package/src/assignment/index.ts +0 -728
- package/src/auth-verifier.ts +0 -227
- package/src/background.ts +0 -183
- package/src/communication-service/template.ts +0 -110
- package/src/communication-service/util.ts +0 -8
- package/src/config/config.ts +0 -211
- package/src/config/env.ts +0 -95
- package/src/config/index.ts +0 -3
- package/src/config/secrets.ts +0 -17
- package/src/context.ts +0 -399
- package/src/daemon/blob-diverter.ts +0 -186
- package/src/daemon/context.ts +0 -247
- package/src/daemon/event-pusher.ts +0 -363
- package/src/daemon/event-reverser.ts +0 -128
- package/src/daemon/index.ts +0 -33
- package/src/daemon/job-cursor.ts +0 -33
- package/src/daemon/materialized-view-refresher.ts +0 -33
- package/src/daemon/queue-router.ts +0 -101
- package/src/daemon/scheduled-action-processor.ts +0 -304
- package/src/daemon/stats-computer.ts +0 -101
- package/src/daemon/strike-expiry-processor.ts +0 -95
- package/src/daemon/team-profile-synchronizer.ts +0 -15
- package/src/daemon/verification-listener.ts +0 -169
- package/src/db/index.ts +0 -203
- package/src/db/migrations/20231219T205730722Z-init.ts +0 -170
- package/src/db/migrations/20240116T085607200Z-communication-template.ts +0 -23
- package/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts +0 -15
- package/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts +0 -31
- package/src/db/migrations/20240228T003647759Z-add-label-sigs.ts +0 -25
- package/src/db/migrations/20240408T192432676Z-mute-reporting.ts +0 -15
- package/src/db/migrations/20240506T225055595Z-message-subject.ts +0 -21
- package/src/db/migrations/20240521T211332580Z-member.ts +0 -17
- package/src/db/migrations/20240814T003647759Z-event-created-at-index.ts +0 -13
- package/src/db/migrations/20240903T205730722Z-add-template-lang.ts +0 -12
- package/src/db/migrations/20240904T205730722Z-add-subject-did-index.ts +0 -13
- package/src/db/migrations/20241001T205730722Z-subject-status-review-state-index.ts +0 -15
- package/src/db/migrations/20241008T205730722Z-sets.ts +0 -53
- package/src/db/migrations/20241018T205730722Z-setting.ts +0 -27
- package/src/db/migrations/20241026T205730722Z-add-hosting-status-to-subject-status.ts +0 -57
- package/src/db/migrations/20241220T144630860Z-stats-materialized-views.ts +0 -215
- package/src/db/migrations/20250204T003647759Z-add-subject-priority-score.ts +0 -22
- package/src/db/migrations/20250211T003647759Z-add-reporter-stats-index.ts +0 -38
- package/src/db/migrations/20250211T132135150Z-moderation-event-message-partial-idx.ts +0 -26
- package/src/db/migrations/20250221T132135150Z-member-details.ts +0 -14
- package/src/db/migrations/20250404T201720309Z-subject-status-sort-idxs.ts +0 -18
- package/src/db/migrations/20250415T201720309Z-verification.ts +0 -34
- package/src/db/migrations/20250417T201720309Z-firehose-cursor.ts +0 -16
- package/src/db/migrations/20250609T110704000Z-safelink.ts +0 -53
- package/src/db/migrations/20250618T180246000Z-add-mod-tool-to-moderation-event.ts +0 -18
- package/src/db/migrations/20250701T000000000Z-add-age-assurance-state.ts +0 -25
- package/src/db/migrations/20250715T000000000Z-add-mod-event-external-id.ts +0 -15
- package/src/db/migrations/20250718T150931000Z-update-appeal-reason-stats.ts +0 -310
- package/src/db/migrations/20250813T000000000Z-mod-tool-batch-id-index.ts +0 -14
- package/src/db/migrations/20250923T000000000Z-scheduled-actions.ts +0 -56
- package/src/db/migrations/20251008T120000000Z-add-strike-system.ts +0 -87
- package/src/db/migrations/20260210T154806448Z-mod-event-created-by-indexes.ts +0 -22
- package/src/db/migrations/20260219T164523000Z-create-report-table.ts +0 -155
- package/src/db/migrations/20260219T165302248Z-moderator-assignment.ts +0 -42
- package/src/db/migrations/20260225T000000000Z-add-report-queue-table.ts +0 -41
- package/src/db/migrations/20260313T000000000Z-add-report-activity-table.ts +0 -48
- package/src/db/migrations/20260318T152058935Z-add-report-stat.ts +0 -35
- package/src/db/migrations/20260428T000000000Z-add-expiring-tag-table.ts +0 -32
- package/src/db/migrations/20260513T202941104Z-add-subject-convo-id.ts +0 -114
- package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +0 -17
- package/src/db/migrations/index.ts +0 -44
- package/src/db/migrations/provider.ts +0 -26
- package/src/db/pagination.ts +0 -335
- package/src/db/schema/account_events_stats.ts +0 -16
- package/src/db/schema/account_record_events_stats.ts +0 -15
- package/src/db/schema/account_record_status_stats.ts +0 -15
- package/src/db/schema/account_strike.ts +0 -13
- package/src/db/schema/blob_push_event.ts +0 -21
- package/src/db/schema/communication_template.ts +0 -19
- package/src/db/schema/expiring_tag.ts +0 -18
- package/src/db/schema/firehose_cursor.ts +0 -13
- package/src/db/schema/index.ts +0 -60
- package/src/db/schema/job_cursor.ts +0 -13
- package/src/db/schema/label.ts +0 -22
- package/src/db/schema/member.ts +0 -22
- package/src/db/schema/moderation_event.ts +0 -61
- package/src/db/schema/moderation_subject_status.ts +0 -52
- package/src/db/schema/moderator_assignment.ts +0 -16
- package/src/db/schema/ozone_set.ts +0 -24
- package/src/db/schema/record_events_stats.ts +0 -15
- package/src/db/schema/record_push_event.ts +0 -21
- package/src/db/schema/repo_push_event.ts +0 -19
- package/src/db/schema/report.ts +0 -28
- package/src/db/schema/report_activity.ts +0 -22
- package/src/db/schema/report_queue.ts +0 -21
- package/src/db/schema/report_stat.ts +0 -27
- package/src/db/schema/safelink.ts +0 -39
- package/src/db/schema/scheduled-action.ts +0 -25
- package/src/db/schema/setting.ts +0 -24
- package/src/db/schema/signing_key.ts +0 -10
- package/src/db/schema/verification.ts +0 -21
- package/src/db/types.ts +0 -24
- package/src/error.ts +0 -12
- package/src/image-invalidator.ts +0 -7
- package/src/index.ts +0 -154
- package/src/jetstream/service.ts +0 -107
- package/src/logger.ts +0 -29
- package/src/mod-service/expiring-tags.ts +0 -104
- package/src/mod-service/index.ts +0 -1842
- package/src/mod-service/profile.ts +0 -139
- package/src/mod-service/report.ts +0 -429
- package/src/mod-service/status.ts +0 -549
- package/src/mod-service/strike.ts +0 -96
- package/src/mod-service/subject.ts +0 -311
- package/src/mod-service/types.ts +0 -96
- package/src/mod-service/util.ts +0 -99
- package/src/mod-service/views.ts +0 -912
- package/src/queue/service.ts +0 -603
- package/src/report/activity.ts +0 -281
- package/src/report/handle-report-update.ts +0 -209
- package/src/report/reassign.ts +0 -109
- package/src/report/stats.ts +0 -852
- package/src/report/views.ts +0 -239
- package/src/safelink/service.ts +0 -304
- package/src/scheduled-action/service.ts +0 -281
- package/src/scheduled-action/types.ts +0 -17
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/outbox.ts +0 -123
- package/src/sequencer/sequencer.ts +0 -147
- package/src/set/service.ts +0 -230
- package/src/setting/constants.ts +0 -3
- package/src/setting/service.ts +0 -148
- package/src/setting/types.ts +0 -3
- package/src/setting/validators.ts +0 -333
- package/src/tag-service/content-tagger.ts +0 -30
- package/src/tag-service/embed-tagger.ts +0 -70
- package/src/tag-service/index.ts +0 -70
- package/src/tag-service/language-data.ts +0 -561
- package/src/tag-service/language-tagger.ts +0 -101
- package/src/tag-service/util.ts +0 -13
- package/src/team/index.ts +0 -296
- package/src/util.ts +0 -230
- package/src/verification/issuer.ts +0 -146
- package/src/verification/service.ts +0 -208
- package/src/verification/util.ts +0 -53
- package/test.env +0 -2
- package/tests/3p-labeler.test.ts +0 -288
- package/tests/__snapshots__/account-strikes.test.ts.snap +0 -159
- package/tests/__snapshots__/age-assurance.test.ts.snap +0 -66
- package/tests/__snapshots__/blob-divert.test.ts.snap +0 -219
- package/tests/__snapshots__/get-account-timeline.test.ts.snap +0 -36
- package/tests/__snapshots__/get-record.test.ts.snap +0 -271
- package/tests/__snapshots__/get-records.test.ts.snap +0 -175
- package/tests/__snapshots__/get-repo.test.ts.snap +0 -91
- package/tests/__snapshots__/get-repos.test.ts.snap +0 -127
- package/tests/__snapshots__/get-starter-pack.test.ts.snap +0 -535
- package/tests/__snapshots__/get-subjects.test.ts.snap +0 -529
- package/tests/__snapshots__/moderation-events.test.ts.snap +0 -347
- package/tests/__snapshots__/moderation-statuses.test.ts.snap +0 -276
- package/tests/__snapshots__/moderation.test.ts.snap +0 -85
- package/tests/__snapshots__/report-reason.test.ts.snap +0 -14
- package/tests/__snapshots__/safelink.test.ts.snap +0 -179
- package/tests/__snapshots__/scheduled-action.test.ts.snap +0 -61
- package/tests/__snapshots__/sets.test.ts.snap +0 -46
- package/tests/__snapshots__/settings.test.ts.snap +0 -52
- package/tests/__snapshots__/team.test.ts.snap +0 -374
- package/tests/__snapshots__/verification-listener.test.ts.snap +0 -152
- package/tests/__snapshots__/verification.test.ts.snap +0 -302
- package/tests/_util.ts +0 -242
- package/tests/account-strikes.test.ts +0 -184
- package/tests/ack-all-subjects-of-account.test.ts +0 -177
- package/tests/age-assurance.test.ts +0 -372
- package/tests/blob-divert.test.ts +0 -106
- package/tests/communication-templates.test.ts +0 -149
- package/tests/content-tagger.test.ts +0 -170
- package/tests/db.test.ts +0 -184
- package/tests/expiring-label.test.ts +0 -72
- package/tests/expiring-tags.test.ts +0 -232
- package/tests/get-account-timeline.test.ts +0 -85
- package/tests/get-config.test.ts +0 -55
- package/tests/get-lists.test.ts +0 -111
- package/tests/get-profiles.test.ts +0 -70
- package/tests/get-record.test.ts +0 -130
- package/tests/get-records.test.ts +0 -91
- package/tests/get-repo.test.ts +0 -171
- package/tests/get-report.test.ts +0 -136
- package/tests/get-reporter-stats.test.ts +0 -132
- package/tests/get-repos.test.ts +0 -91
- package/tests/get-starter-pack.test.ts +0 -115
- package/tests/get-subjects.test.ts +0 -81
- package/tests/mod-tool.test.ts +0 -268
- package/tests/moderation-appeals.test.ts +0 -260
- package/tests/moderation-events.test.ts +0 -756
- package/tests/moderation-status-tags.test.ts +0 -140
- package/tests/moderation-statuses.test.ts +0 -495
- package/tests/moderation.test.ts +0 -992
- package/tests/protected-tags.test.ts +0 -218
- package/tests/query-labels.test.ts +0 -238
- package/tests/query-reports.test.ts +0 -608
- package/tests/queue-assignment.test.ts +0 -428
- package/tests/queue-router.test.ts +0 -306
- package/tests/queues.test.ts +0 -690
- package/tests/record-and-account-events.test.ts +0 -197
- package/tests/repo-search.test.ts +0 -136
- package/tests/report-action.test.ts +0 -308
- package/tests/report-activity.test.ts +0 -711
- package/tests/report-assignment.test.ts +0 -517
- package/tests/report-muting.test.ts +0 -100
- package/tests/report-reason.test.ts +0 -154
- package/tests/report-reassign-queue.test.ts +0 -340
- package/tests/report-routing.test.ts +0 -245
- package/tests/report-stats.test.ts +0 -545
- package/tests/revoke-account-credentials.test.ts +0 -54
- package/tests/safelink.test.ts +0 -534
- package/tests/scheduled-action-processor.test.ts +0 -488
- package/tests/scheduled-action.test.ts +0 -334
- package/tests/sequencer.test.ts +0 -227
- package/tests/server.test.ts +0 -62
- package/tests/sets.test.ts +0 -246
- package/tests/settings.test.ts +0 -308
- package/tests/strike-expiry-processor.test.ts +0 -299
- package/tests/subject-priority-score.test.ts +0 -96
- package/tests/takedown.test.ts +0 -105
- package/tests/team.test.ts +0 -216
- package/tests/verification-listener.test.ts +0 -129
- package/tests/verification.test.ts +0 -186
- package/tsconfig.build.json +0 -9
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import AtpAgent from '@atproto/api'
|
|
2
|
-
import { SECOND } from '@atproto/common'
|
|
3
|
-
import {
|
|
4
|
-
ModeratorClient,
|
|
5
|
-
SeedClient,
|
|
6
|
-
TestNetwork,
|
|
7
|
-
basicSeed,
|
|
8
|
-
} from '@atproto/dev-env'
|
|
9
|
-
import { ids } from '../src/lexicon/lexicons.js'
|
|
10
|
-
import { SeverityLevelSettingKey } from '../src/setting/constants.js'
|
|
11
|
-
|
|
12
|
-
const strikeConfig = {
|
|
13
|
-
'sev-1': {
|
|
14
|
-
strikeCount: 1,
|
|
15
|
-
expiresInDays: 0, // Set to 0 so we can use future timestamps
|
|
16
|
-
},
|
|
17
|
-
'sev-2': {
|
|
18
|
-
strikeCount: 2,
|
|
19
|
-
expiresInDays: 0,
|
|
20
|
-
},
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
describe('strike expiry processor', () => {
|
|
24
|
-
let network: TestNetwork
|
|
25
|
-
let agent: AtpAgent
|
|
26
|
-
let sc: SeedClient
|
|
27
|
-
let modClient: ModeratorClient
|
|
28
|
-
|
|
29
|
-
const repoSubject = (did: string) => ({
|
|
30
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
31
|
-
did,
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
const configureSeverityLevels = async () => {
|
|
35
|
-
await agent.tools.ozone.setting.upsertOption(
|
|
36
|
-
{
|
|
37
|
-
scope: 'instance',
|
|
38
|
-
key: SeverityLevelSettingKey,
|
|
39
|
-
value: strikeConfig,
|
|
40
|
-
description: 'Severity level configuration for strike system',
|
|
41
|
-
managerRole: 'tools.ozone.team.defs#roleAdmin',
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
encoding: 'application/json',
|
|
45
|
-
headers: await network.ozone.modHeaders(
|
|
46
|
-
ids.ToolsOzoneSettingUpsertOption,
|
|
47
|
-
'admin',
|
|
48
|
-
),
|
|
49
|
-
},
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const getAccountStatus = async (did: string) => {
|
|
54
|
-
const { subjectStatuses } = await modClient.queryStatuses({ subject: did })
|
|
55
|
-
return subjectStatuses[0]
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
beforeAll(async () => {
|
|
59
|
-
network = await TestNetwork.create({
|
|
60
|
-
dbPostgresSchema: 'ozone_strike_expiry_processor',
|
|
61
|
-
})
|
|
62
|
-
agent = network.ozone.getAgent()
|
|
63
|
-
sc = network.getSeedClient()
|
|
64
|
-
modClient = network.ozone.getModClient()
|
|
65
|
-
await basicSeed(sc)
|
|
66
|
-
await network.processAll()
|
|
67
|
-
await configureSeverityLevels()
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
afterAll(async () => {
|
|
71
|
-
await network?.close()
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('processes expired strikes and updates active strike count', async () => {
|
|
75
|
-
const bobDid = sc.dids.bob
|
|
76
|
-
const bobPost1 = {
|
|
77
|
-
$type: 'com.atproto.repo.strongRef',
|
|
78
|
-
uri: sc.posts[bobDid][0].ref.uriStr,
|
|
79
|
-
cid: sc.posts[bobDid][0].ref.cidStr,
|
|
80
|
-
}
|
|
81
|
-
const bobPost2 = {
|
|
82
|
-
$type: 'com.atproto.repo.strongRef',
|
|
83
|
-
uri: sc.posts[bobDid][1].ref.uriStr,
|
|
84
|
-
cid: sc.posts[bobDid][1].ref.cidStr,
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// first strike on a post that expires in 2 seconds
|
|
88
|
-
const expiresAt1 = new Date(Date.now() + 2 * SECOND).toISOString()
|
|
89
|
-
await modClient.emitEvent({
|
|
90
|
-
event: {
|
|
91
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
92
|
-
severityLevel: 'sev-2',
|
|
93
|
-
strikeCount: 2,
|
|
94
|
-
strikeExpiresAt: expiresAt1,
|
|
95
|
-
comment: 'First violation - expires soon',
|
|
96
|
-
},
|
|
97
|
-
subject: bobPost1,
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
// second strike on another post that expires in 3 seconds
|
|
101
|
-
const expiresAt2 = new Date(Date.now() + 3 * SECOND).toISOString()
|
|
102
|
-
await modClient.emitEvent({
|
|
103
|
-
event: {
|
|
104
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
105
|
-
strikeCount: 1,
|
|
106
|
-
severityLevel: 'sev-1',
|
|
107
|
-
strikeExpiresAt: expiresAt2,
|
|
108
|
-
comment: 'Second violation - expires later',
|
|
109
|
-
},
|
|
110
|
-
subject: bobPost2,
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
// account-level event to ensure account status is created
|
|
114
|
-
await modClient.emitEvent({
|
|
115
|
-
event: {
|
|
116
|
-
$type: 'tools.ozone.moderation.defs#modEventComment',
|
|
117
|
-
comment: 'Account under review',
|
|
118
|
-
},
|
|
119
|
-
subject: repoSubject(bobDid),
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
// Verify initial state - both strikes are active
|
|
123
|
-
let status = await getAccountStatus(bobDid)
|
|
124
|
-
expect(status.accountStrike).toBeDefined()
|
|
125
|
-
expect(status.accountStrike!.activeStrikeCount).toBe(3) // 2 + 1
|
|
126
|
-
expect(status.accountStrike!.totalStrikeCount).toBe(3)
|
|
127
|
-
|
|
128
|
-
// Wait for first strike to expire
|
|
129
|
-
await new Promise((resolve) => setTimeout(resolve, 2.1 * SECOND))
|
|
130
|
-
|
|
131
|
-
// Run the processor
|
|
132
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
133
|
-
|
|
134
|
-
// Verify first strike expired - only second strike remains active
|
|
135
|
-
status = await getAccountStatus(bobDid)
|
|
136
|
-
expect(status.accountStrike).toBeDefined()
|
|
137
|
-
expect(status.accountStrike!.activeStrikeCount).toBe(1) // Only second strike
|
|
138
|
-
expect(status.accountStrike!.totalStrikeCount).toBe(3) // Total unchanged
|
|
139
|
-
|
|
140
|
-
// Wait for second strike to expire
|
|
141
|
-
await new Promise((resolve) => setTimeout(resolve, 1 * SECOND))
|
|
142
|
-
|
|
143
|
-
// Run the processor again
|
|
144
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
145
|
-
|
|
146
|
-
// Verify all strikes expired
|
|
147
|
-
status = await getAccountStatus(bobDid)
|
|
148
|
-
expect(status.accountStrike).toBeDefined()
|
|
149
|
-
expect(status.accountStrike!.activeStrikeCount).toBe(0)
|
|
150
|
-
expect(status.accountStrike!.totalStrikeCount).toBe(3) // Total unchanged
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('handles accounts with no expired strikes', async () => {
|
|
154
|
-
const aliceDid = sc.dids.alice
|
|
155
|
-
|
|
156
|
-
// strike that expires far in the future
|
|
157
|
-
const expiresAt = new Date(Date.now() + 1000 * SECOND).toISOString()
|
|
158
|
-
await modClient.emitEvent({
|
|
159
|
-
event: {
|
|
160
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
161
|
-
severityLevel: 'sev-2',
|
|
162
|
-
strikeCount: 2,
|
|
163
|
-
strikeExpiresAt: expiresAt,
|
|
164
|
-
comment: 'Future expiry',
|
|
165
|
-
},
|
|
166
|
-
subject: repoSubject(aliceDid),
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
// Get initial state
|
|
170
|
-
let status = await getAccountStatus(aliceDid)
|
|
171
|
-
expect(status.accountStrike).toBeDefined()
|
|
172
|
-
const initialActiveCount = status.accountStrike!.activeStrikeCount!
|
|
173
|
-
expect(initialActiveCount).toBe(2)
|
|
174
|
-
|
|
175
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
176
|
-
|
|
177
|
-
// Verify nothing changed
|
|
178
|
-
status = await getAccountStatus(aliceDid)
|
|
179
|
-
expect(status.accountStrike).toBeDefined()
|
|
180
|
-
expect(status.accountStrike!.activeStrikeCount).toBe(initialActiveCount)
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
it('handles strikes with no expiry date (permanent strikes)', async () => {
|
|
184
|
-
const carolDid = sc.dids.carol
|
|
185
|
-
|
|
186
|
-
// permanent strike (no expiry)
|
|
187
|
-
await modClient.emitEvent({
|
|
188
|
-
event: {
|
|
189
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
190
|
-
severityLevel: 'sev-2',
|
|
191
|
-
strikeCount: 2,
|
|
192
|
-
comment: 'Permanent strike - no expiry',
|
|
193
|
-
},
|
|
194
|
-
subject: repoSubject(carolDid),
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
// Get initial state
|
|
198
|
-
let status = await getAccountStatus(carolDid)
|
|
199
|
-
expect(status.accountStrike).toBeDefined()
|
|
200
|
-
expect(status.accountStrike!.activeStrikeCount).toBe(2)
|
|
201
|
-
|
|
202
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
203
|
-
|
|
204
|
-
// Verify permanent strikes remain active
|
|
205
|
-
status = await getAccountStatus(carolDid)
|
|
206
|
-
expect(status.accountStrike).toBeDefined()
|
|
207
|
-
expect(status.accountStrike!.activeStrikeCount).toBe(2)
|
|
208
|
-
expect(status.accountStrike!.totalStrikeCount).toBe(2)
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('processes multiple accounts with expired strikes in batch', async () => {
|
|
212
|
-
const danDid = 'did:plc:dan'
|
|
213
|
-
const eveDid = 'did:plc:eve'
|
|
214
|
-
|
|
215
|
-
const expiresAt = new Date(Date.now() + 1 * SECOND).toISOString()
|
|
216
|
-
|
|
217
|
-
// strikes to multiple accounts
|
|
218
|
-
await modClient.emitEvent({
|
|
219
|
-
event: {
|
|
220
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
221
|
-
severityLevel: 'sev-1',
|
|
222
|
-
strikeCount: 1,
|
|
223
|
-
strikeExpiresAt: expiresAt,
|
|
224
|
-
comment: 'Dan violation',
|
|
225
|
-
},
|
|
226
|
-
subject: repoSubject(danDid),
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
await modClient.emitEvent({
|
|
230
|
-
event: {
|
|
231
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
232
|
-
severityLevel: 'sev-2',
|
|
233
|
-
strikeCount: 2,
|
|
234
|
-
strikeExpiresAt: expiresAt,
|
|
235
|
-
comment: 'Eve violation',
|
|
236
|
-
},
|
|
237
|
-
subject: repoSubject(eveDid),
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
// Verify initial states
|
|
241
|
-
let danStatus = await getAccountStatus(danDid)
|
|
242
|
-
let eveStatus = await getAccountStatus(eveDid)
|
|
243
|
-
expect(danStatus.accountStrike?.activeStrikeCount).toBe(1)
|
|
244
|
-
expect(eveStatus.accountStrike?.activeStrikeCount).toBe(2)
|
|
245
|
-
|
|
246
|
-
// Wait for strikes to expire
|
|
247
|
-
await new Promise((resolve) => setTimeout(resolve, 1.1 * SECOND))
|
|
248
|
-
|
|
249
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
250
|
-
|
|
251
|
-
// Verify both accounts' strikes expired
|
|
252
|
-
danStatus = await getAccountStatus(danDid)
|
|
253
|
-
eveStatus = await getAccountStatus(eveDid)
|
|
254
|
-
expect(danStatus.accountStrike?.activeStrikeCount).toBe(0)
|
|
255
|
-
expect(eveStatus.accountStrike?.activeStrikeCount).toBe(0)
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
it('updates cursor to track last processed timestamp', async () => {
|
|
259
|
-
const frankDid = 'did:plc:frank'
|
|
260
|
-
const expiresAt = new Date(Date.now() + 1 * SECOND).toISOString()
|
|
261
|
-
|
|
262
|
-
await modClient.emitEvent({
|
|
263
|
-
event: {
|
|
264
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
265
|
-
severityLevel: 'sev-1',
|
|
266
|
-
strikeCount: 1,
|
|
267
|
-
strikeExpiresAt: expiresAt,
|
|
268
|
-
comment: 'Frank violation',
|
|
269
|
-
},
|
|
270
|
-
subject: repoSubject(frankDid),
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
// Wait for strike to expire
|
|
274
|
-
await new Promise((resolve) => setTimeout(resolve, 1.1 * SECOND))
|
|
275
|
-
|
|
276
|
-
// Get cursor before processing
|
|
277
|
-
const cursorBefore =
|
|
278
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.getCursor()
|
|
279
|
-
|
|
280
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
281
|
-
|
|
282
|
-
// Get cursor after processing
|
|
283
|
-
const cursorAfter =
|
|
284
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.getCursor()
|
|
285
|
-
|
|
286
|
-
expect(cursorAfter).not.toBe(cursorBefore)
|
|
287
|
-
expect(cursorAfter).toBeTruthy()
|
|
288
|
-
|
|
289
|
-
// Verify strike was processed
|
|
290
|
-
const status = await getAccountStatus(frankDid)
|
|
291
|
-
expect(status.accountStrike?.activeStrikeCount).toBe(0)
|
|
292
|
-
|
|
293
|
-
// running processor again should not reprocess the same strike
|
|
294
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.processExpiredStrikes()
|
|
295
|
-
const cursorAfterSecond =
|
|
296
|
-
await network.ozone.daemon.ctx.strikeExpiryProcessor.getCursor()
|
|
297
|
-
expect(cursorAfterSecond).not.toBe(cursorAfter)
|
|
298
|
-
})
|
|
299
|
-
})
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ModeratorClient,
|
|
3
|
-
SeedClient,
|
|
4
|
-
TestNetwork,
|
|
5
|
-
basicSeed,
|
|
6
|
-
} from '@atproto/dev-env'
|
|
7
|
-
import { REASONSPAM } from '../dist/lexicon/types/com/atproto/moderation/defs.js'
|
|
8
|
-
|
|
9
|
-
describe('moderation', () => {
|
|
10
|
-
let network: TestNetwork
|
|
11
|
-
let sc: SeedClient
|
|
12
|
-
let modClient: ModeratorClient
|
|
13
|
-
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
network = await TestNetwork.create({
|
|
16
|
-
dbPostgresSchema: 'ozone_priority_score',
|
|
17
|
-
})
|
|
18
|
-
sc = network.getSeedClient()
|
|
19
|
-
modClient = network.ozone.getModClient()
|
|
20
|
-
await basicSeed(sc)
|
|
21
|
-
await Promise.all([
|
|
22
|
-
sc.createReport({
|
|
23
|
-
reasonType: REASONSPAM,
|
|
24
|
-
subject: {
|
|
25
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
26
|
-
did: sc.dids.bob,
|
|
27
|
-
},
|
|
28
|
-
reportedBy: sc.dids.carol,
|
|
29
|
-
}),
|
|
30
|
-
sc.createReport({
|
|
31
|
-
reasonType: REASONSPAM,
|
|
32
|
-
subject: {
|
|
33
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
34
|
-
did: sc.dids.alice,
|
|
35
|
-
},
|
|
36
|
-
reportedBy: sc.dids.carol,
|
|
37
|
-
}),
|
|
38
|
-
sc.createReport({
|
|
39
|
-
reasonType: REASONSPAM,
|
|
40
|
-
subject: {
|
|
41
|
-
$type: 'com.atproto.repo.strongRef',
|
|
42
|
-
uri: sc.posts[sc.dids.bob][0].ref.uriStr,
|
|
43
|
-
cid: sc.posts[sc.dids.bob][0].ref.cidStr,
|
|
44
|
-
},
|
|
45
|
-
reportedBy: sc.dids.carol,
|
|
46
|
-
}),
|
|
47
|
-
])
|
|
48
|
-
await network.processAll()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
afterAll(async () => {
|
|
52
|
-
await network?.close()
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('allows setting a priority score.', async () => {
|
|
56
|
-
const { subjectStatuses: before } = await modClient.queryStatuses({})
|
|
57
|
-
await Promise.all([
|
|
58
|
-
modClient.emitEvent({
|
|
59
|
-
subject: before[before.length - 1].subject,
|
|
60
|
-
event: {
|
|
61
|
-
$type: 'tools.ozone.moderation.defs#modEventPriorityScore',
|
|
62
|
-
score: 10,
|
|
63
|
-
},
|
|
64
|
-
}),
|
|
65
|
-
modClient.emitEvent({
|
|
66
|
-
subject: before[before.length - 2].subject,
|
|
67
|
-
event: {
|
|
68
|
-
$type: 'tools.ozone.moderation.defs#modEventPriorityScore',
|
|
69
|
-
score: 5,
|
|
70
|
-
},
|
|
71
|
-
}),
|
|
72
|
-
])
|
|
73
|
-
const { subjectStatuses: after } = await modClient.queryStatuses({
|
|
74
|
-
sortDirection: 'desc',
|
|
75
|
-
sortField: 'priorityScore',
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
// Verify that highest priority score item is first
|
|
79
|
-
expect(after[0].priorityScore).toBe(10)
|
|
80
|
-
expect(after[1].priorityScore).toBe(5)
|
|
81
|
-
expect(after[0].subject).toMatchObject(before[before.length - 1].subject)
|
|
82
|
-
expect(after[1].subject).toMatchObject(before[before.length - 2].subject)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('allows setting a priority score.', async () => {
|
|
86
|
-
const { subjectStatuses } = await modClient.queryStatuses({
|
|
87
|
-
minPriorityScore: 6,
|
|
88
|
-
sortDirection: 'desc',
|
|
89
|
-
sortField: 'priorityScore',
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
// Verify that highest priority score item is first
|
|
93
|
-
expect(subjectStatuses[0].priorityScore).toBe(10)
|
|
94
|
-
expect(subjectStatuses.length).toBe(1)
|
|
95
|
-
})
|
|
96
|
-
})
|
package/tests/takedown.test.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import {
|
|
3
|
-
AtpAgent,
|
|
4
|
-
ComAtprotoAdminDefs,
|
|
5
|
-
ToolsOzoneModerationDefs,
|
|
6
|
-
} from '@atproto/api'
|
|
7
|
-
import {
|
|
8
|
-
ModeratorClient,
|
|
9
|
-
SeedClient,
|
|
10
|
-
TestNetwork,
|
|
11
|
-
basicSeed,
|
|
12
|
-
} from '@atproto/dev-env'
|
|
13
|
-
|
|
14
|
-
describe('moderation', () => {
|
|
15
|
-
let network: TestNetwork
|
|
16
|
-
|
|
17
|
-
let sc: SeedClient
|
|
18
|
-
let modClient: ModeratorClient
|
|
19
|
-
let pdsAgent: AtpAgent
|
|
20
|
-
let bskyAgent: AtpAgent
|
|
21
|
-
|
|
22
|
-
const repoSubject = (did: string) => ({
|
|
23
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
24
|
-
did,
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
beforeAll(async () => {
|
|
28
|
-
network = await TestNetwork.create({
|
|
29
|
-
dbPostgresSchema: 'ozone_takedown',
|
|
30
|
-
})
|
|
31
|
-
sc = network.getSeedClient()
|
|
32
|
-
modClient = network.ozone.getModClient()
|
|
33
|
-
pdsAgent = network.pds.getAgent()
|
|
34
|
-
bskyAgent = network.bsky.getAgent()
|
|
35
|
-
await basicSeed(sc)
|
|
36
|
-
await network.processAll()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
afterAll(async () => {
|
|
40
|
-
await network?.close()
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('allows specifying policy for takedown actions.', async () => {
|
|
44
|
-
await modClient.performTakedown({
|
|
45
|
-
subject: repoSubject(sc.dids.bob),
|
|
46
|
-
policies: ['trolling'],
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
// Verify that that the takedown even exposes the policy specified for it
|
|
50
|
-
const { events: eventViews } = await modClient.queryEvents({
|
|
51
|
-
subject: sc.dids.bob,
|
|
52
|
-
types: ['tools.ozone.moderation.defs#modEventTakedown'],
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
const { event } = eventViews[0]
|
|
56
|
-
|
|
57
|
-
assert(ToolsOzoneModerationDefs.isModEventTakedown(event))
|
|
58
|
-
expect(event.policies?.[0]).toEqual('trolling')
|
|
59
|
-
|
|
60
|
-
// Verify that event stream can be filtered by policy
|
|
61
|
-
const { events: filteredEvents } = await modClient.queryEvents({
|
|
62
|
-
subject: sc.dids.bob,
|
|
63
|
-
policies: ['trolling'],
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
const { subject } = filteredEvents[0]
|
|
67
|
-
|
|
68
|
-
assert(ComAtprotoAdminDefs.isRepoRef(subject))
|
|
69
|
-
expect(subject.did).toEqual(sc.dids.bob)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('applies takedown only to specified service when targetServices is set', async () => {
|
|
73
|
-
await modClient.emitEvent({
|
|
74
|
-
event: {
|
|
75
|
-
$type: 'tools.ozone.moderation.defs#modEventTakedown',
|
|
76
|
-
targetServices: ['appview'],
|
|
77
|
-
},
|
|
78
|
-
subject: repoSubject(sc.dids.carol),
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
await network.processAll()
|
|
82
|
-
|
|
83
|
-
const [pdsStatus, appviewStatus, carolsEvents] = await Promise.all([
|
|
84
|
-
pdsAgent.com.atproto.admin.getSubjectStatus(
|
|
85
|
-
{ did: sc.dids.carol },
|
|
86
|
-
{ headers: network.pds.adminAuthHeaders() },
|
|
87
|
-
),
|
|
88
|
-
bskyAgent.com.atproto.admin.getSubjectStatus(
|
|
89
|
-
{ did: sc.dids.carol },
|
|
90
|
-
{ headers: network.bsky.adminAuthHeaders() },
|
|
91
|
-
),
|
|
92
|
-
modClient.queryEvents({
|
|
93
|
-
subject: sc.dids.carol,
|
|
94
|
-
types: ['tools.ozone.moderation.defs#modEventTakedown'],
|
|
95
|
-
}),
|
|
96
|
-
])
|
|
97
|
-
|
|
98
|
-
expect(pdsStatus.data.takedown?.applied).toBe(false)
|
|
99
|
-
expect(appviewStatus.data.takedown?.applied).toBe(true)
|
|
100
|
-
|
|
101
|
-
const event = carolsEvents.events[0].event
|
|
102
|
-
assert(ToolsOzoneModerationDefs.isModEventTakedown(event))
|
|
103
|
-
expect(event.targetServices).toEqual(['appview'])
|
|
104
|
-
})
|
|
105
|
-
})
|