Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 0 additions & 75 deletions one-off/redact-story-name-and-description.sql

This file was deleted.

112 changes: 112 additions & 0 deletions one-off/redact-story-name-desc-customtext.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Redact the name, description, and selected custom text/long-text fields of a story,
* and delete any commits or webhook events that include those fields in their payload.
*
* INSTRUCTIONS:
* 1. Set @storyNumber to the Story number to redact
* 2. Set @customTextDefinition if any custom text field needs to be redacted
* 3. Set @customLongTextDefinition if any custom long text field needs to be redacted
* 4. Review the messages printed by the script to verify that it is updating the expected records
* 5. Set @saveChanges=1
* 6. Rerun the script to commit the changes
*
* NOTE: This script defaults to rolling back changes.
* To commit changes, set @saveChanges = 1.
*/
declare @storyNumber int=NNNNN
declare @customTextDefinition varchar(201)=NULL -- e.g. 'AssetType.Custom_text_field'
declare @customLongTextDefinition varchar(201)=NULL -- e.g. 'AssetType.Custom_long_text_field'
declare @saveChanges bit; set @saveChanges = 1

declare @customTextFieldName varchar(201)=case
when @customTextDefinition is not null and charindex('.', @customTextDefinition) > 0
then right(@customTextDefinition, charindex('.', reverse(@customTextDefinition)) - 1)
end
declare @customLongTextFieldName varchar(201)=case
when @customLongTextDefinition is not null and charindex('.', @customLongTextDefinition) > 0
then right(@customLongTextDefinition, charindex('.', reverse(@customLongTextDefinition)) - 1)
end

declare @storyId int
select @storyId=ID from dbo.Workitem_Now where AssetType='Story' and Number=@storyNumber

if (@storyId is null) begin
raiserror('S-%d not found', 16, 1, @storyNumber)
return
end
raiserror('Found Story:%d', 0, 1, @storyId) with nowait

declare @storyOid varchar(max)='Story:'+cast(@storyId as varchar(max))+':%'
declare @redacted nvarchar(max)=N'redacted'
declare @hash int=BINARY_CHECKSUM(@redacted)

set nocount on; begin tran; save tran tx
declare @error int, @rowcount int

update dbo.String
set Value=@redacted, Hash=@hash
from dbo.BaseAsset
where String.ID=Name and BaseAsset.ID=@storyId

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Names redacted', 0, 1, @rowcount) with nowait

update dbo.LongString
set Value=@redacted
from dbo.BaseAsset
where LongString.ID=Description and BaseAsset.ID=@storyId

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Descriptions redacted', 0, 1, @rowcount) with nowait

update dbo.String
set Value=@redacted, Hash=@hash
from dbo.CustomText
where @customTextDefinition is not null and String.ID=CustomText.Value and CustomText.ID=@storyId
and CustomText.Definition = @customTextDefinition

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Custom Text redacted', 0, 1, @rowcount) with nowait

update dbo.LongString
set Value=@redacted
from dbo.CustomLongText
where @customLongTextDefinition is not null and LongString.ID=CustomLongText.Value and CustomLongText.ID=@storyId
and CustomLongText.Definition = @customLongTextDefinition

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Custom Long Text redacted', 0, 1, @rowcount) with nowait

delete dbo.Commits
where cast(Payload as varchar(max)) like '%Asset":"'+@storyOid and (
cast(Payload as varchar(max)) like '%"Name":"Name"%' or
cast(Payload as varchar(max)) like '%"Name":"Description"%' or
cast(Payload as varchar(max)) like '%"Name":"' + @customTextFieldName + '"%' or
cast(Payload as varchar(max)) like '%"Name":"' + @customLongTextFieldName + '"%'
)

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Commits deleted', 0, 1, @rowcount) with nowait

delete dbo.WebhookEvents
where cast(Payload as varchar(max)) like '%oid":"'+@storyOid and (
cast(Payload as varchar(max)) like '%"name":"Name"%' or
cast(Payload as varchar(max)) like '%"name":"Description"%' or
cast(Payload as varchar(max)) like '%"name":"' + @customTextFieldName + '"%' or
cast(Payload as varchar(max)) like '%"name":"' + @customLongTextFieldName + '"%'
)

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d WebhookEvents deleted', 0, 1, @rowcount) with nowait

if @saveChanges=1 goto OK
raiserror('Rolling back changes. To commit changes, set @saveChanges=1', 16, 1)
ERR: rollback tran tx
OK: commit

71 changes: 71 additions & 0 deletions one-off/redact-workitem-tags.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
This script redacts a specific tag associated with a specific workitem.
Set @workitemNumber to the number of the workitem you want to redact.
Set @assetType to the type of the workitem (e.g., 'Story').
Set @tagValue to the exact tag value to redact.
Set @replaceWith to the value that will replace the tag.
Set @saveChanges to 1 to commit changes, or 0 to roll back.
*/

declare @workitemNumber int=NNNNN
declare @assetType varchar(100)=NULL -- e.g. 'Story'
declare @tagValue nvarchar(440)=NULL -- e.g. 'item for review' (the literal tag value)
declare @replaceWith nvarchar(440)='redacted'

@spazmodius spazmodius Sep 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
declare @replaceWith nvarchar(440)='redacted'
declare @replaceWith nvarchar(440)=N'redacted-' + cast(newid() as nvarchar(max))

declare @saveChanges bit; --set @saveChanges = 1

declare @workitemId int
select @workitemId=ID from dbo.Workitem_Now where AssetType=@assetType and Number=@workitemNumber

if (@workitemId is null) begin
raiserror('%d not found', 16, 1, @workitemNumber)
return
end
raiserror('Found %s:%d', 0, 1, @assetType, @workitemId) with nowait

if exists (
select 1
from dbo.BaseAssetTaggedWith
where ID=@workitemId
and Value=@replaceWith
and Value<>@tagValue
) begin
raiserror('Replacement tag already exists in this workitem''s history', 16, 1)
return
end

declare @workitemOid varchar(max)=@assetType+':'+cast(@workitemId as varchar(max))+':%'

set nocount on; begin tran; save tran tx
declare @error int, @rowcount int

update dbo.BaseAssetTaggedWith
set Value=@replaceWith
where ID=@workitemId and Value=@tagValue
Comment thread
spazmodius marked this conversation as resolved.

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Tags deleted', 0, 1, @rowcount) with nowait

declare @encodedTag as nvarchar (max) = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@tagValue, N'\', N'\\'), N'"', N'\"'), N'~', N'~~'), N'%', N'~%'), N'_', N'~_'), N'[', N'~[');

delete dbo.Commits
where cast(Payload as varchar(max)) like '%Asset":"'+@workitemOid
and cast(Payload as varchar(max)) like '%"Name":"TaggedWith"%Value":"'+@encodedTag+'"%' ESCAPE N'~';


select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d Commits deleted', 0, 1, @rowcount) with nowait

delete dbo.WebhookEvents
where cast(Payload as varchar(max)) like '%oid":"'+@workitemOid
and cast(Payload as varchar(max)) like '%"name":"TaggedWith"%"new":"'+@encodedTag+'"%' ESCAPE N'~';

select @rowcount=@@ROWCOUNT, @error=@@ERROR
if @error<>0 goto ERR
raiserror('%d WebhookEvents deleted', 0, 1, @rowcount) with nowait

if @saveChanges=1 goto OK
raiserror('Rolling back changes. To commit changes, set @saveChanges=1', 16, 1)
ERR: rollback tran tx
OK: commit