From bc802195f5b3c67c100fb94c0052edf5f7740c7d Mon Sep 17 00:00:00 2001 From: Hariharan Ayyappan Date: Thu, 17 Sep 2026 20:15:00 +0530 Subject: [PATCH 1/7] S-137651 Updated script to redact custom text fields and remove tag values from story --- one-off/redact-story-name-and-description.sql | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/one-off/redact-story-name-and-description.sql b/one-off/redact-story-name-and-description.sql index 50dd1d6..3ad80e3 100644 --- a/one-off/redact-story-name-and-description.sql +++ b/one-off/redact-story-name-and-description.sql @@ -1,19 +1,32 @@ /* - * Redact the name and description of a story, + * Redact the name, description, tags, custom text and longtext fields of a story, * along with any commits or webhook events that contain the name or description in their payload. * * INSTRUCTIONS: * 1. Set @storyNumber to the Story number to redact - * 2. Review the messages printed by the script to verify that it is updating the expected records - * 3. Set @saveChanges=1 - * 4. Rerun the script to commit the changes + * 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)='AssetType.Custom_text_field' +declare @customLongTextDefinition varchar(201)='AssetType.Custom_long_text_field' declare @saveChanges bit; --set @saveChanges = 1 +declare @customTextFieldName varchar(201)= right( + @customTextDefinition, + charindex('.', reverse(@customTextDefinition)) - 1 + ) +declare @customLongTextFieldName varchar(201) = right( + @customLongTextDefinition, + charindex('.', reverse(@customLongTextDefinition)) - 1 + ) + declare @storyId int select @storyId=ID from dbo.Workitem_Now where AssetType='Story' and Number=@storyNumber @@ -48,10 +61,40 @@ 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 String.ID=CustomText.Value and CustomText.ID=@storyId +and CustomText.Definition in (@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 LongString.ID=CustomLongText.Value and CustomLongText.ID=@storyId +and CustomLongText.Definition in (@customLongTextDefinition) + +select @rowcount=@@ROWCOUNT, @error=@@ERROR +if @error<>0 goto ERR +raiserror('%d Custom Long Text redacted', 0, 1, @rowcount) with nowait + +delete dbo.BaseAssetTaggedWith +where ID=@storyId + +select @rowcount=@@ROWCOUNT, @error=@@ERROR +if @error<>0 goto ERR +raiserror('%d Tags deleted', 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"%' +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":"TaggedWith"%' or +cast(Payload as varchar(max)) like '%"Name":"' + @customTextFieldName + '"%' or +cast(Payload as varchar(max)) like '%"Name":"' + @customLongTextFieldName + '"%' ) select @rowcount=@@ROWCOUNT, @error=@@ERROR @@ -61,7 +104,10 @@ 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"%' + cast(Payload as varchar(max)) like '%"name":"Description"%' or + cast(Payload as varchar(max)) like '%"name":"TaggedWith"%' or + cast(Payload as varchar(max)) like '%"name":"' + @customTextFieldName + '"%' or + cast(Payload as varchar(max)) like '%"name":"' + @customLongTextFieldName + '"%' ) select @rowcount=@@ROWCOUNT, @error=@@ERROR From aeb532eb4a1705be6093acd35f2a94580104d010 Mon Sep 17 00:00:00 2001 From: Hariharan Ayyappan Date: Thu, 17 Sep 2026 20:17:33 +0530 Subject: [PATCH 2/7] S-137651 Renamed redact script --- ...n.sql => redact-story-multiple-fields.sql} | 242 +++++++++--------- 1 file changed, 121 insertions(+), 121 deletions(-) rename one-off/{redact-story-name-and-description.sql => redact-story-multiple-fields.sql} (97%) diff --git a/one-off/redact-story-name-and-description.sql b/one-off/redact-story-multiple-fields.sql similarity index 97% rename from one-off/redact-story-name-and-description.sql rename to one-off/redact-story-multiple-fields.sql index 3ad80e3..8b3a889 100644 --- a/one-off/redact-story-name-and-description.sql +++ b/one-off/redact-story-multiple-fields.sql @@ -1,121 +1,121 @@ -/* - * Redact the name, description, tags, custom text and longtext fields of a story, - * along with any commits or webhook events that contain the name or description 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)='AssetType.Custom_text_field' -declare @customLongTextDefinition varchar(201)='AssetType.Custom_long_text_field' -declare @saveChanges bit; --set @saveChanges = 1 - -declare @customTextFieldName varchar(201)= right( - @customTextDefinition, - charindex('.', reverse(@customTextDefinition)) - 1 - ) -declare @customLongTextFieldName varchar(201) = right( - @customLongTextDefinition, - charindex('.', reverse(@customLongTextDefinition)) - 1 - ) - -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 String.ID=CustomText.Value and CustomText.ID=@storyId -and CustomText.Definition in (@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 LongString.ID=CustomLongText.Value and CustomLongText.ID=@storyId -and CustomLongText.Definition in (@customLongTextDefinition) - -select @rowcount=@@ROWCOUNT, @error=@@ERROR -if @error<>0 goto ERR -raiserror('%d Custom Long Text redacted', 0, 1, @rowcount) with nowait - -delete dbo.BaseAssetTaggedWith -where ID=@storyId - -select @rowcount=@@ROWCOUNT, @error=@@ERROR -if @error<>0 goto ERR -raiserror('%d Tags deleted', 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":"TaggedWith"%' 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":"TaggedWith"%' 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 - +/* + * Redact the name, description, tags, custom text and longtext fields of a story, + * along with any commits or webhook events that contain the name or description 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)='AssetType.Custom_text_field' +declare @customLongTextDefinition varchar(201)='AssetType.Custom_long_text_field' +declare @saveChanges bit; --set @saveChanges = 1 + +declare @customTextFieldName varchar(201)= right( + @customTextDefinition, + charindex('.', reverse(@customTextDefinition)) - 1 + ) +declare @customLongTextFieldName varchar(201) = right( + @customLongTextDefinition, + charindex('.', reverse(@customLongTextDefinition)) - 1 + ) + +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 String.ID=CustomText.Value and CustomText.ID=@storyId +and CustomText.Definition in (@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 LongString.ID=CustomLongText.Value and CustomLongText.ID=@storyId +and CustomLongText.Definition in (@customLongTextDefinition) + +select @rowcount=@@ROWCOUNT, @error=@@ERROR +if @error<>0 goto ERR +raiserror('%d Custom Long Text redacted', 0, 1, @rowcount) with nowait + +delete dbo.BaseAssetTaggedWith +where ID=@storyId + +select @rowcount=@@ROWCOUNT, @error=@@ERROR +if @error<>0 goto ERR +raiserror('%d Tags deleted', 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":"TaggedWith"%' 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":"TaggedWith"%' 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 + From 2baacb2a7cca0936c64c15a8a797ba72fcea6c38 Mon Sep 17 00:00:00 2001 From: Hariharan Ayyappan Date: Fri, 18 Sep 2026 13:53:36 +0530 Subject: [PATCH 3/7] S-137651 Addressed copilot comments - updated header comment - used = instead in for definition comparison --- one-off/redact-story-multiple-fields.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/one-off/redact-story-multiple-fields.sql b/one-off/redact-story-multiple-fields.sql index 8b3a889..c6a6800 100644 --- a/one-off/redact-story-multiple-fields.sql +++ b/one-off/redact-story-multiple-fields.sql @@ -1,6 +1,6 @@ /* - * Redact the name, description, tags, custom text and longtext fields of a story, - * along with any commits or webhook events that contain the name or description in their payload. + * Redact the name, description, tags, 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 @@ -65,7 +65,7 @@ update dbo.String set Value=@redacted, Hash=@hash from dbo.CustomText where String.ID=CustomText.Value and CustomText.ID=@storyId -and CustomText.Definition in (@customTextDefinition) +and CustomText.Definition = @customTextDefinition select @rowcount=@@ROWCOUNT, @error=@@ERROR if @error<>0 goto ERR @@ -75,7 +75,7 @@ update dbo.LongString set Value=@redacted from dbo.CustomLongText where LongString.ID=CustomLongText.Value and CustomLongText.ID=@storyId -and CustomLongText.Definition in (@customLongTextDefinition) +and CustomLongText.Definition = @customLongTextDefinition select @rowcount=@@ROWCOUNT, @error=@@ERROR if @error<>0 goto ERR From 1f726d1822abb21842d29ef98c0a590e730b5db8 Mon Sep 17 00:00:00 2001 From: Hariharan Ayyappan Date: Fri, 18 Sep 2026 23:16:02 +0530 Subject: [PATCH 4/7] S-137651 Move deleting tags to separate script file --- ... => redact-story-name-desc-customtext.sql} | 39 ++++++-------- one-off/redact-workitem-tags.sql | 53 +++++++++++++++++++ 2 files changed, 68 insertions(+), 24 deletions(-) rename one-off/{redact-story-multiple-fields.sql => redact-story-name-desc-customtext.sql} (76%) create mode 100644 one-off/redact-workitem-tags.sql diff --git a/one-off/redact-story-multiple-fields.sql b/one-off/redact-story-name-desc-customtext.sql similarity index 76% rename from one-off/redact-story-multiple-fields.sql rename to one-off/redact-story-name-desc-customtext.sql index c6a6800..e679e75 100644 --- a/one-off/redact-story-multiple-fields.sql +++ b/one-off/redact-story-name-desc-customtext.sql @@ -1,5 +1,5 @@ /* - * Redact the name, description, tags, and selected custom text/long-text fields of a story, + * 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: @@ -14,18 +14,18 @@ * To commit changes, set @saveChanges = 1. */ declare @storyNumber int=NNNNN -declare @customTextDefinition varchar(201)='AssetType.Custom_text_field' -declare @customLongTextDefinition varchar(201)='AssetType.Custom_long_text_field' -declare @saveChanges bit; --set @saveChanges = 1 - -declare @customTextFieldName varchar(201)= right( - @customTextDefinition, - charindex('.', reverse(@customTextDefinition)) - 1 - ) -declare @customLongTextFieldName varchar(201) = right( - @customLongTextDefinition, - charindex('.', reverse(@customLongTextDefinition)) - 1 - ) +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 @@ -64,7 +64,7 @@ raiserror('%d Descriptions redacted', 0, 1, @rowcount) with nowait update dbo.String set Value=@redacted, Hash=@hash from dbo.CustomText -where String.ID=CustomText.Value and CustomText.ID=@storyId +where @customTextDefinition is not null and String.ID=CustomText.Value and CustomText.ID=@storyId and CustomText.Definition = @customTextDefinition select @rowcount=@@ROWCOUNT, @error=@@ERROR @@ -74,25 +74,17 @@ raiserror('%d Custom Text redacted', 0, 1, @rowcount) with nowait update dbo.LongString set Value=@redacted from dbo.CustomLongText -where LongString.ID=CustomLongText.Value and CustomLongText.ID=@storyId +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.BaseAssetTaggedWith -where ID=@storyId - -select @rowcount=@@ROWCOUNT, @error=@@ERROR -if @error<>0 goto ERR -raiserror('%d Tags deleted', 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":"TaggedWith"%' or cast(Payload as varchar(max)) like '%"Name":"' + @customTextFieldName + '"%' or cast(Payload as varchar(max)) like '%"Name":"' + @customLongTextFieldName + '"%' ) @@ -105,7 +97,6 @@ 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":"TaggedWith"%' or cast(Payload as varchar(max)) like '%"name":"' + @customTextFieldName + '"%' or cast(Payload as varchar(max)) like '%"name":"' + @customLongTextFieldName + '"%' ) diff --git a/one-off/redact-workitem-tags.sql b/one-off/redact-workitem-tags.sql new file mode 100644 index 0000000..391ccc5 --- /dev/null +++ b/one-off/redact-workitem-tags.sql @@ -0,0 +1,53 @@ +/* +This script redacts tags 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 @saveChanges to 1 to commit changes, or 0 to roll back. +*/ + +declare @workitemNumber int=NNNNN +declare @assetType varchar(100)=NULL -- e.g. 'Story' +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 + +declare @workitemOid varchar(max)=@assetType+':'+cast(@workitemId as varchar(max))+':%' + +set nocount on; begin tran; save tran tx +declare @error int, @rowcount int + +delete dbo.BaseAssetTaggedWith +where ID=@workitemId + +select @rowcount=@@ROWCOUNT, @error=@@ERROR +if @error<>0 goto ERR +raiserror('%d Tags deleted', 0, 1, @rowcount) with nowait + +delete dbo.Commits +where cast(Payload as varchar(max)) like '%Asset":"'+@workitemOid +and cast(Payload as varchar(max)) like '%"Name":"TaggedWith"%' + + +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"%' + +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 \ No newline at end of file From 4e74fe3a024fc205ef35238a2b0bab8e1502ef2c Mon Sep 17 00:00:00 2001 From: Hariharan Ayyappan Date: Sat, 19 Sep 2026 00:34:51 +0530 Subject: [PATCH 5/7] S-137651: Update script to redact tags instead of deleting them --- one-off/redact-workitem-tags.sql | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/one-off/redact-workitem-tags.sql b/one-off/redact-workitem-tags.sql index 391ccc5..e4c8cf0 100644 --- a/one-off/redact-workitem-tags.sql +++ b/one-off/redact-workitem-tags.sql @@ -7,6 +7,8 @@ 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 varchar(440)=NULL -- e.g. 'all' +declare @replaceWith varchar(440)='redacted' declare @saveChanges bit; set @saveChanges = 1 declare @workitemId int @@ -23,8 +25,9 @@ declare @workitemOid varchar(max)=@assetType+':'+cast(@workitemId as varchar(max set nocount on; begin tran; save tran tx declare @error int, @rowcount int -delete dbo.BaseAssetTaggedWith -where ID=@workitemId +update dbo.BaseAssetTaggedWith +set Value=@replaceWith +where ID=@workitemId and Value=@tagValue select @rowcount=@@ROWCOUNT, @error=@@ERROR if @error<>0 goto ERR @@ -32,7 +35,7 @@ raiserror('%d Tags deleted', 0, 1, @rowcount) with nowait delete dbo.Commits where cast(Payload as varchar(max)) like '%Asset":"'+@workitemOid -and cast(Payload as varchar(max)) like '%"Name":"TaggedWith"%' +and cast(Payload as varchar(max)) like '%"Name":"TaggedWith"%Value":"'+@tagValue+'"%' select @rowcount=@@ROWCOUNT, @error=@@ERROR @@ -41,7 +44,7 @@ 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"%' +and cast(Payload as varchar(max)) like '%"name":"TaggedWith"%"new":"'+@tagValue+'"%' select @rowcount=@@ROWCOUNT, @error=@@ERROR if @error<>0 goto ERR From 1462a8cf6bc6fa7aa8959c969c8eb1c1011cce67 Mon Sep 17 00:00:00 2001 From: Hariharan Ayyappan Date: Tue, 22 Sep 2026 23:32:19 +0530 Subject: [PATCH 6/7] S-137651 Addressed review comments - Updated @tagValue comment and included it in the heade block - Added condition to check weather replacement tag value already present in the asset - Json encoded tag value --- one-off/redact-workitem-tags.sql | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/one-off/redact-workitem-tags.sql b/one-off/redact-workitem-tags.sql index e4c8cf0..24f8455 100644 --- a/one-off/redact-workitem-tags.sql +++ b/one-off/redact-workitem-tags.sql @@ -1,15 +1,17 @@ /* -This script redacts tags associated with a specific workitem. +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 varchar(440)=NULL -- e.g. 'all' -declare @replaceWith varchar(440)='redacted' -declare @saveChanges bit; set @saveChanges = 1 +declare @tagValue nvarchar(440)=NULL -- e.g. 'item for review' (the literal tag value) +declare @replaceWith nvarchar(440)='redacted' +declare @saveChanges bit; --set @saveChanges = 1 declare @workitemId int select @workitemId=ID from dbo.Workitem_Now where AssetType=@assetType and Number=@workitemNumber @@ -20,6 +22,17 @@ if (@workitemId is null) begin 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 @@ -33,9 +46,11 @@ 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":"'+@tagValue+'"%' +and cast(Payload as varchar(max)) like '%"Name":"TaggedWith"%Value":"'+@encodedTag+'"%' ESCAPE N'~'; select @rowcount=@@ROWCOUNT, @error=@@ERROR @@ -44,7 +59,7 @@ 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":"'+@tagValue+'"%' +and cast(Payload as varchar(max)) like '%"name":"TaggedWith"%"new":"'+@encodedTag+'"%' ESCAPE N'~'; select @rowcount=@@ROWCOUNT, @error=@@ERROR if @error<>0 goto ERR From 0d7be0444a9afbeaaea53fa34fe4285bf025e0be Mon Sep 17 00:00:00 2001 From: hariharan-digitalai <113446111+hariharan-digitalai@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:32:45 +0530 Subject: [PATCH 7/7] Generate a new replaceWith value on every run Co-authored-by: rajiv --- one-off/redact-workitem-tags.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/one-off/redact-workitem-tags.sql b/one-off/redact-workitem-tags.sql index 24f8455..ca0e9a6 100644 --- a/one-off/redact-workitem-tags.sql +++ b/one-off/redact-workitem-tags.sql @@ -10,7 +10,7 @@ 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' +declare @replaceWith nvarchar(440)=N'redacted-' + cast(newid() as nvarchar(max)) declare @saveChanges bit; --set @saveChanges = 1 declare @workitemId int