From d7c9734c75c00e92735588e1e48bb7148725df3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:58:18 +0000 Subject: [PATCH 01/19] Initial plan From 13c6195c30719b8e73ee52b18e34d61de089671b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:51:18 +0100 Subject: [PATCH 02/19] Add documentation and tests that maxBy/minBy return the first max/min element (#19464) Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- src/FSharp.Core/array.fsi | 6 ++++-- src/FSharp.Core/list.fsi | 6 ++++-- src/FSharp.Core/seq.fsi | 9 +++++---- .../Microsoft.FSharp.Collections/ArrayModule2.fs | 8 ++++++++ .../Microsoft.FSharp.Collections/ListModule2.fs | 8 ++++++++ .../Microsoft.FSharp.Collections/SeqModule2.fs | 8 ++++++++ 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 59e6377ffe4..503e3ee6900 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -1895,7 +1895,8 @@ module Array = /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. /// - /// Throws ArgumentException for empty arrays. This is an O(n) operation, where n is the length of the array. + /// Returns the first maximal element of the array if there are multiple equal maximum elements. + /// Throws ArgumentException for empty arrays. This is an O(n) operation, where n is the length of the array. /// /// The function to transform the elements into a type supporting comparison. /// The input array. @@ -1958,7 +1959,8 @@ module Array = /// Returns the lowest of all elements of the array, compared via Operators.min on the function result. /// - /// Throws ArgumentException for empty arrays. This is an O(n) operation, where n is the length of the array. + /// Returns the first minimal element of the array if there are multiple equal minimal elements. + /// Throws ArgumentException for empty arrays. This is an O(n) operation, where n is the length of the array. /// /// The function to transform the elements into a type supporting comparison. /// The input array. diff --git a/src/FSharp.Core/list.fsi b/src/FSharp.Core/list.fsi index a16c3c1e328..af7ddf2aeef 100644 --- a/src/FSharp.Core/list.fsi +++ b/src/FSharp.Core/list.fsi @@ -1573,7 +1573,8 @@ module List = /// Returns the greatest of all elements of the list, compared via Operators.max on the function result. /// - /// Raises if list is empty. This is an O(n) operation, where n is the length of the list. + /// Returns the first maximal element of the list if there are multiple equal maximum elements. + /// Raises if list is empty. This is an O(n) operation, where n is the length of the list. /// The function to transform the list elements into the type to be compared. /// The input list. /// @@ -1632,7 +1633,8 @@ module List = /// Returns the lowest of all elements of the list, compared via Operators.min on the function result /// - /// Raises if list is empty. This is an O(n) operation, where n is the length of the list. + /// Returns the first minimal element of the list if there are multiple equal minimal elements. + /// Raises if list is empty. This is an O(n) operation, where n is the length of the list. /// The function to transform list elements into the type to be compared. /// The input list. /// diff --git a/src/FSharp.Core/seq.fsi b/src/FSharp.Core/seq.fsi index b793b63e6de..86f09996263 100644 --- a/src/FSharp.Core/seq.fsi +++ b/src/FSharp.Core/seq.fsi @@ -1779,6 +1779,8 @@ module Seq = /// Returns the greatest of all elements of the sequence, compared via Operators.max on the function result. /// + /// Returns the first maximal element of the sequence if there are multiple equal maximum elements. + /// This is an O(n) operation, where n is the length of the sequence. /// A function to transform items from the input sequence into comparable keys. /// The input sequence. /// @@ -1804,8 +1806,6 @@ module Seq = /// /// Throws System.ArgumentException. /// - /// - /// This is an O(n) operation, where n is the length of the sequence. [] val inline maxBy: projection: ('T -> 'U) -> source: seq<'T> -> 'T when 'U: comparison @@ -1842,6 +1842,9 @@ module Seq = /// Returns the lowest of all elements of the sequence, compared via Operators.min on the function result. /// + /// Returns the first minimal element of the sequence if there are multiple equal minimal elements. + /// This is an O(n) operation, where n is the length of the sequence. + /// /// A function to transform items from the input sequence into comparable keys. /// The input sequence. /// @@ -1867,8 +1870,6 @@ module Seq = /// /// Throws System.ArgumentException. /// - /// - /// This is an O(n) operation, where n is the length of the sequence. [] val inline minBy: projection: ('T -> 'U) -> source: seq<'T> -> 'T when 'U: comparison diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index b0532b8929f..837574aefdc 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -304,6 +304,10 @@ type ArrayModule2() = // len = 0 CheckThrowsArgumentException(fun() -> Array.maxBy funcInt (Array.empty) |> ignore) + // returns first maximal element + let max = Array.maxBy fst [|1, "a"; 2, "b"; 3, "c"; 2, "d"; 3, "e"; 1, "f" |] + if snd max <> "c" then Assert.Fail() + () [] @@ -348,6 +352,10 @@ type ArrayModule2() = // len = 0 CheckThrowsArgumentException(fun () -> Array.minBy funcInt (Array.empty) |> ignore) + // returns first minimal element + let min = Array.minBy fst [|3, "a"; 2, "b"; 1, "c"; 2, "d"; 1, "e"; 3, "f" |] + if snd min <> "c" then Assert.Fail() + () diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs index 3a27d4e7d2a..ab3b0365d69 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs @@ -291,6 +291,10 @@ type ListModule02() = // empty List CheckThrowsArgumentException ( fun() -> List.maxBy (fun () -> 1) List.empty ) + // returns first maximal element + let max = List.maxBy fst [1, "a"; 2, "b"; 3, "c"; 2, "d"; 3, "e"; 1, "f" ] + if snd max <> "c" then Assert.Fail() + () [] @@ -324,6 +328,10 @@ type ListModule02() = let funcEpt () = 1 CheckThrowsArgumentException ( fun() -> List.minBy funcEpt List.empty) + // returns first minimal element + let min = List.minBy fst [ 3, "a"; 2, "b"; 1, "c"; 2, "d"; 1, "e"; 3, "f" ] + if snd min <> "c" then Assert.Fail() + () [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs index db3b8a3adcc..9ac290935fe 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs @@ -969,6 +969,10 @@ type SeqModule2() = let nullSeq:seq<'a> = null CheckThrowsArgumentNullException (fun () ->Seq.maxBy funcInt nullSeq |> ignore) + // returns first maximal element + let max = Seq.maxBy fst (seq { 1, "a"; 2, "b"; 3, "c"; 2, "d"; 3, "e"; 1, "f" }) + if snd max <> "c" then Assert.Fail() + () [] @@ -991,6 +995,10 @@ type SeqModule2() = let nullSeq:seq<'a> = null CheckThrowsArgumentNullException (fun () ->Seq.minBy funcInt nullSeq |> ignore) + // returns first minimal element + let min = Seq.minBy fst (seq { 3, "a"; 2, "b"; 1, "c"; 2, "d"; 1, "e"; 3, "f" }) + if snd min <> "c" then Assert.Fail() + () From 91a387e0a45e89ffd0c11126cb4fe3109aff5ed6 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 27 Mar 2026 19:26:16 +0100 Subject: [PATCH 03/19] Bugfix :: Fix type definition metadata: duplicate methods, event flags (#19341) Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 3 + .../Checking/Expressions/CheckExpressions.fs | 6 +- src/Compiler/CodeGen/IlxGen.fs | 29 +- .../CodeGenRegressions_TypeDefs.fs | 289 ++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 5 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_TypeDefs.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 7bf923dd503..d5c2087765e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +1,8 @@ ### Fixed +* Fix DU case names matching IWSAM member names no longer cause duplicate property entries. (Issue [#14321](https://github.com/dotnet/fsharp/issues/14321), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) +* Fix DefaultAugmentation(false) duplicate entry in method table. (Issue [#16565](https://github.com/dotnet/fsharp/issues/16565), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) +* Fix abstract event accessors now have SpecialName flag. (Issue [#5834](https://github.com/dotnet/fsharp/issues/5834), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) * Fix CLIEvent properties to be correctly recognized as events: `IsEvent` returns `true` and `XmlDocSig` uses `E:` prefix instead of `P:`. ([Issue #10273](https://github.com/dotnet/fsharp/issues/10273), [PR #18584](https://github.com/dotnet/fsharp/pull/18584)) * Fix extra sequence point at the end of match expressions. ([Issue #12052](https://github.com/dotnet/fsharp/issues/12052), [PR #19278](https://github.com/dotnet/fsharp/pull/19278)) * Fix wrong sequence point range for `return`/`yield`/`return!`/`yield!` inside computation expressions. ([Issue #19248](https://github.com/dotnet/fsharp/issues/19248), [PR #19278](https://github.com/dotnet/fsharp/pull/19278)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 3fd84ee6c09..635a0dff045 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -13146,7 +13146,11 @@ let TcAndPublishValSpec (cenv: cenv, env, containerInfo: ContainerInfo, declKind let checkXmlDocs = cenv.diagnosticOptions.CheckXmlDocs let xmlDoc = xmlDoc.ToXmlDoc(checkXmlDocs, paramNames) - let vspec = MakeAndPublishVal cenv env (altActualParent, true, declKind, ValNotInRecScope, valscheme, attrs, xmlDoc, literalValue, false) + let isGeneratedEventVal = + CompileAsEvent g attrs + && (id.idText.StartsWithOrdinal("add_") || id.idText.StartsWithOrdinal("remove_")) + + let vspec = MakeAndPublishVal cenv env (altActualParent, true, declKind, ValNotInRecScope, valscheme, attrs, xmlDoc, literalValue, isGeneratedEventVal) PublishArguments cenv env vspec synValSig allDeclaredTypars.Length diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 14a966ad068..4e3452a2d8e 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -10903,6 +10903,13 @@ and GenAbstractBinding cenv eenv tref (vref: ValRef) = | SynMemberKind.Constructor | SynMemberKind.Member -> let mdef = mdef.With(customAttrs = mkILCustomAttrs ilAttrs) + + let mdef = + if vref.Deref.val_flags.IsGeneratedEventVal then + mdef.WithSpecialName + else + mdef + [ mdef ], [], [] | SynMemberKind.PropertyGetSet -> error (Error(FSComp.SR.ilUnexpectedGetSetAnnotation (), m)) | SynMemberKind.PropertySet @@ -11927,6 +11934,17 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option // // Also discard the F#-compiler supplied implementation of the Empty, IsEmpty, Value and None properties. + let nullaryCaseNames = + if cuinfo.HasHelpers = AllHelpers || cuinfo.HasHelpers = NoHelpers then + cuinfo.UnionCases + |> Array.choose (fun alt -> if alt.IsNullary then Some alt.Name else None) + |> Set.ofArray + else + Set.empty + + let isNullaryCaseClash name = + not nullaryCaseNames.IsEmpty && nullaryCaseNames.Contains name + let tdefDiscards = Some( (fun (md: ILMethodDef) -> @@ -11935,7 +11953,11 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option || (cuinfo.HasHelpers = SpecialFSharpOptionHelpers && (md.Name = "get_Value" || md.Name = "get_None" || md.Name = "Some")) || (cuinfo.HasHelpers = AllHelpers - && (md.Name.StartsWith("get_Is") && not (tdef2.Methods.FindByName(md.Name).IsEmpty)))), + && (md.Name.StartsWith("get_Is") && not (tdef2.Methods.FindByName(md.Name).IsEmpty))) + || (md.Name.StartsWith("get_") + && md.Name.Length > 4 + && isNullaryCaseClash (md.Name.Substring(4)) + && not (tdef2.Methods.FindByName(md.Name).IsEmpty))), (fun (pd: ILPropertyDef) -> (cuinfo.HasHelpers = SpecialFSharpListHelpers @@ -11943,7 +11965,10 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option || (cuinfo.HasHelpers = SpecialFSharpOptionHelpers && (pd.Name = "Value" || pd.Name = "None")) || (cuinfo.HasHelpers = AllHelpers - && (pd.Name.StartsWith("Is") && not (tdef2.Properties.LookupByName(pd.Name).IsEmpty)))) + && (pd.Name.StartsWith("Is") && not (tdef2.Properties.LookupByName(pd.Name).IsEmpty))) + || (isNullaryCaseClash pd.Name + && (not (tdef2.Properties.LookupByName(pd.Name).IsEmpty) + || not (tdef2.Methods.FindByName("get_" + pd.Name).IsEmpty)))) ) tdef2, tdefDiscards diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_TypeDefs.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_TypeDefs.fs new file mode 100644 index 00000000000..0fe36c5bf33 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/CodeGenRegressions/CodeGenRegressions_TypeDefs.fs @@ -0,0 +1,289 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace EmittedIL + +open Xunit +open FSharp.Test +open FSharp.Test.Compiler + +module CodeGenRegressions_TypeDefs = + + // https://github.com/dotnet/fsharp/issues/16565 + [] + let ``Issue_16565_DefaultAugmentationFalseDuplicateEntry`` () = + let source = """ +module Test + +open System + +[] +type Option<'T> = + | Some of Value: 'T + | None + + member x.Value = + match x with + | Some x -> x + | None -> raise (new InvalidOperationException("Option.Value")) + + static member None : Option<'T> = None + +and 'T option = Option<'T> + +let v = Option.Some 42 +printfn "Value: %d" v.Value +let n = Option.None +printfn "None created successfully" +""" + FSharp source + |> asExe + |> compile + |> shouldSucceed + |> run + |> shouldSucceed + |> ignore + + // https://github.com/dotnet/fsharp/issues/14321 + [] + let ``Issue_14321_DuAndIWSAMNames`` () = + let source = """ +module Test + +#nowarn "3535" // IWSAM warning + +type EngineError<'e> = + static abstract Overheated : 'e + static abstract LowOil : 'e + +type CarError = + | Overheated + | LowOil + | DeviceNotPaired + + interface EngineError with + static member Overheated = Overheated + static member LowOil = LowOil +""" + FSharp source + |> asLibrary + |> compile + |> shouldSucceed + |> ignore + + // https://github.com/dotnet/fsharp/issues/14321 + // Runtime test: type must load without "duplicate entry in method table" + [] + let ``Issue_14321_DuAndIWSAMNames_Runtime`` () = + let source = """ +module Test + +#nowarn "3535" + +type EngineError<'e> = + static abstract Overheated : 'e + static abstract LowOil : 'e + +type CarError = + | Overheated + | LowOil + | DeviceNotPaired + + interface EngineError with + static member Overheated = Overheated + static member LowOil = LowOil + +[] +let main _ = + let err = CarError.Overheated + match err with + | Overheated -> printfn "Got Overheated" + | LowOil -> printfn "Got LowOil" + | DeviceNotPaired -> printfn "Got DeviceNotPaired" + 0 +""" + FSharp source + |> asExe + |> compile + |> shouldSucceed + |> run + |> shouldSucceed + |> ignore + + // https://github.com/dotnet/fsharp/issues/5834 + [] + let ``Issue_5834_EventSpecialname`` () = + let source = """ +module Test + +open System +open System.Reflection + +type IAbstract1 = + [] + abstract member Event : IEvent + +type IAbstract2 = + [] + abstract member Event : IDelegateEvent + +[] +type Abstract3() = + [] + abstract member Event : IDelegateEvent + +type Concrete1() = + let event = new Event() + [] + member this.Event = event.Publish + +type Concrete2() = + [] + member this.Event = { new IDelegateEvent with + member this.AddHandler _ = () + member this.RemoveHandler _ = () } + +type ConcreteWithObsolete() = + let evt = new Event() + [] + [] + member this.MyEvent = evt.Publish + +[] +let main _ = + let mutable failures = 0 + let check (t: Type) = + t.GetMethods(BindingFlags.Public ||| BindingFlags.Instance ||| BindingFlags.DeclaredOnly) + |> Array.filter (fun m -> m.Name.Contains("Event")) + |> Array.iter (fun m -> + if not m.IsSpecialName then + printfn "FAIL: %s.%s missing specialname" t.Name m.Name + failures <- failures + 1) + + check typeof + check typeof + check typeof + check typeof + check typeof + check typeof + + if failures > 0 then + failwithf "BUG: %d event accessors missing specialname" failures + printfn "SUCCESS: All event accessors have specialname" + 0 +""" + FSharp source + |> asExe + |> compile + |> shouldSucceed + |> run + |> shouldSucceed + |> ignore + + // https://github.com/dotnet/fsharp/issues/5834 + // IL verification: abstract event accessors must have specialname flag + [] + let ``Issue_5834_EventSpecialname_IL`` () = + let source = """ +module Test + +open System + +type IAbstract1 = + [] + abstract member Event : IEvent + +[] +type Abstract2() = + [] + abstract member Event : IDelegateEvent +""" + FSharp source + |> asLibrary + |> compile + |> shouldSucceed + |> verifyIL [ + // Interface abstract event accessors have specialname + """.method public hidebysig specialname abstract virtual instance void add_Event(class [runtime]System.EventHandler A_1) cil managed""" + + """.method public hidebysig specialname abstract virtual instance void remove_Event(class [runtime]System.EventHandler A_1) cil managed""" + + // IAbstract1 event references its accessors + """.addon instance void Test/IAbstract1::add_Event(class [runtime]System.EventHandler)""" + """.removeon instance void Test/IAbstract1::remove_Event(class [runtime]System.EventHandler)""" + + // Abstract2 event also references its specialname accessors + """.addon instance void Test/Abstract2::add_Event(class [runtime]System.EventHandler)""" + """.removeon instance void Test/Abstract2::remove_Event(class [runtime]System.EventHandler)""" + ] + |> ignore + + // https://github.com/dotnet/fsharp/issues/14321 + // IL verification: DU case properties and IWSAM implementations coexist without duplicates + [] + let ``Issue_14321_DuAndIWSAMNames_IL`` () = + let source = """ +module Test + +#nowarn "3535" + +type EngineError<'e> = + static abstract Overheated : 'e + static abstract LowOil : 'e + +type CarError = + | Overheated + | LowOil + | DeviceNotPaired + + interface EngineError with + static member Overheated = Overheated + static member LowOil = LowOil +""" + FSharp source + |> asLibrary + |> compile + |> shouldSucceed + |> verifyIL [ + // DU case property getter exists on CarError + """.method public static class Test/CarError get_Overheated() cil managed""" + + // Explicit IWSAM implementation uses mangled name + """.method public hidebysig specialname static class Test/CarError 'Test.EngineError.get_Overheated'() cil managed""" + + // Explicit IWSAM for LowOil also present + """.method public hidebysig specialname static class Test/CarError 'Test.EngineError.get_LowOil'() cil managed""" + ] + |> ignore + + // https://github.com/dotnet/fsharp/issues/16565 + // IL verification: DefaultAugmentation(false) produces no duplicate method table entries + [] + let ``Issue_16565_DefaultAugmentationFalseDuplicateEntry_IL`` () = + let source = """ +module Test + +[] +type MyOption<'T> = + | Some of Value: 'T + | None + + member x.Value = + match x with + | Some x -> x + | None -> failwith "no value" + + static member None : MyOption<'T> = None +""" + FSharp source + |> asLibrary + |> compile + |> shouldSucceed + |> verifyIL [ + // The user-defined get_Value method exists on the main type with specialname + """.method public hidebysig specialname instance !T get_Value() cil managed""" + + // The static get_None method exists + """.method public static class Test/MyOption`1 get_None() cil managed""" + ] + |> ignore + diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index b02548a438c..f5d1048408e 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -280,6 +280,7 @@ + From 348aeb721bdbd45233a1a4e1bc874a0ca2643cfa Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 27 Mar 2026 19:28:39 +0100 Subject: [PATCH 04/19] resolve integrity issues in gh aw (#19510) Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .github/agents/agentic-workflows.agent.md | 28 +++--- .github/aw/actions-lock.json | 17 ++-- .github/workflows/repo-assist.lock.yml | 111 ++++++++++------------ .github/workflows/repo-assist.md | 1 + 4 files changed, 72 insertions(+), 85 deletions(-) diff --git a/.github/agents/agentic-workflows.agent.md b/.github/agents/agentic-workflows.agent.md index 47092725f98..7ed300e00cc 100644 --- a/.github/agents/agentic-workflows.agent.md +++ b/.github/agents/agentic-workflows.agent.md @@ -30,7 +30,7 @@ Workflows may optionally include: - Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` - Workflow lock files: `.github/workflows/*.lock.yml` - Shared components: `.github/workflows/shared/*.md` -- Configuration: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/github-agentic-workflows.md +- Configuration: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/github-agentic-workflows.md ## Problems This Solves @@ -52,7 +52,7 @@ When you interact with this agent, it will: ### Create New Workflow **Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/create-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/create-agentic-workflow.md **Use cases**: - "Create a workflow that triages issues" @@ -62,7 +62,7 @@ When you interact with this agent, it will: ### Update Existing Workflow **Load when**: User wants to modify, improve, or refactor an existing workflow -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/update-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/update-agentic-workflow.md **Use cases**: - "Add web-fetch tool to the issue-classifier workflow" @@ -72,7 +72,7 @@ When you interact with this agent, it will: ### Debug Workflow **Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/debug-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/debug-agentic-workflow.md **Use cases**: - "Why is this workflow failing?" @@ -82,7 +82,7 @@ When you interact with this agent, it will: ### Upgrade Agentic Workflows **Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/upgrade-agentic-workflows.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/upgrade-agentic-workflows.md **Use cases**: - "Upgrade all workflows to the latest version" @@ -92,7 +92,7 @@ When you interact with this agent, it will: ### Create a Report-Generating Workflow **Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/report.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/report.md **Use cases**: - "Create a weekly CI health report" @@ -102,7 +102,7 @@ When you interact with this agent, it will: ### Create Shared Agentic Workflow **Load when**: User wants to create a reusable workflow component or wrap an MCP server -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/create-shared-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/create-shared-agentic-workflow.md **Use cases**: - "Create a shared component for Notion integration" @@ -110,19 +110,19 @@ When you interact with this agent, it will: - "Design a shared workflow for database queries" ### Fix Dependabot PRs -**Load when**: User needs to close or fix an open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) +**Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/dependabot.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/dependabot.md **Use cases**: -- "Fix open Dependabot PRs for npm dependencies" -- "Bundle and close Dependabot PRs for workflow dependencies" +- "Fix the open Dependabot PRs for npm dependencies" +- "Bundle and close the Dependabot PRs for workflow dependencies" - "Update @playwright/test to fix the Dependabot PR" ### Analyze Test Coverage **Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/test-coverage.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/test-coverage.md **Use cases**: - "Create a workflow that comments coverage on PRs" @@ -169,10 +169,10 @@ gh aw compile --validate ## Important Notes -- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/github-agentic-workflows.md for complete documentation +- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/github-agentic-workflows.md for complete documentation - Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud - Workflows must be compiled to `.lock.yml` files before running in GitHub Actions - **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF - Follow security best practices: minimal permissions, explicit network access, no template injection -- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.64.0/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. - **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 5db6600c72f..a3de9b4b5d1 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -5,20 +5,15 @@ "version": "v8", "sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd" }, - "github/gh-aw-actions/setup@v0.62.0": { + "github/gh-aw-actions/setup@v0.64.2": { "repo": "github/gh-aw-actions/setup", - "version": "v0.62.0", - "sha": "b2c35f34e1013dd9ed2a84c559e2b2fec9ad38e6" + "version": "v0.64.2", + "sha": "f22886a9607f5c27e79742a8bfc5faa34737138b" }, - "github/gh-aw-actions/setup@v0.64.0": { - "repo": "github/gh-aw-actions/setup", - "version": "v0.64.0", - "sha": "51c65948c64ab6752536ead71fba1fc2c20ed0bc" - }, - "github/gh-aw/actions/setup@v0.64.0": { + "github/gh-aw/actions/setup@v0.64.2": { "repo": "github/gh-aw/actions/setup", - "version": "v0.64.0", - "sha": "f684e4c1d3be9417db83fbd553fb84de2809c165" + "version": "v0.64.2", + "sha": "72346ee09bdaa904d167f1be907e590fd9128fa3" } } } diff --git a/.github/workflows/repo-assist.lock.yml b/.github/workflows/repo-assist.lock.yml index b1bd1422b2d..e28af9c044b 100644 --- a/.github/workflows/repo-assist.lock.yml +++ b/.github/workflows/repo-assist.lock.yml @@ -12,7 +12,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.64.0). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.64.2). DO NOT EDIT. # # To update this file, edit githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02 and run: # gh aw compile @@ -35,7 +35,7 @@ # # Source: githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02 # -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d75bcc7a75f547113f447da58a55e31496f5d71e97c382008b2356d2a3893cc0","compiler_version":"v0.64.0","strict":true,"agent_id":"copilot"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"1bb4c53e8ede8f6c3a7e9d9a0fdc6f804d5abda2a2657c0831e4a4c9689822e4","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot"} name: "Repo Assist" "on": @@ -105,7 +105,7 @@ jobs: title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Generate agentic run info @@ -116,14 +116,14 @@ jobs: GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} GH_AW_INFO_VERSION: "latest" GH_AW_INFO_AGENT_VERSION: "latest" - GH_AW_INFO_CLI_VERSION: "v0.64.0" + GH_AW_INFO_CLI_VERSION: "v0.64.2" GH_AW_INFO_WORKFLOW_NAME: "Repo Assist" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","python"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.0" + GH_AW_INFO_AWF_VERSION: "v0.25.1" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -212,15 +212,15 @@ jobs: run: | bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh { - cat << 'GH_AW_PROMPT_EOF' + cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' - GH_AW_PROMPT_EOF + GH_AW_PROMPT_5cd45711b7cf54eb_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/repo_memory_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_EOF' + cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' Tools: add_comment(max:10), create_issue(max:4), update_issue, add_labels(max:30), missing_tool, missing_data, noop @@ -252,17 +252,17 @@ jobs: {{/if}} - GH_AW_PROMPT_EOF + GH_AW_PROMPT_5cd45711b7cf54eb_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md" fi - cat << 'GH_AW_PROMPT_EOF' + cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' + GH_AW_PROMPT_5cd45711b7cf54eb_EOF + cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' {{#runtime-import .github/workflows/repo-assist.md}} - GH_AW_PROMPT_EOF + GH_AW_PROMPT_5cd45711b7cf54eb_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -373,7 +373,7 @@ jobs: output_types: ${{ steps.collect_output.outputs.output_types }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Set runtime paths @@ -433,30 +433,26 @@ jobs: env: GH_HOST: github.com - name: Install AWF binary - run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.0 - - name: Determine automatic lockdown mode for GitHub MCP Server - id: determine-automatic-lockdown - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + - name: Parse integrity filter lists + id: parse-guard-vars env: - GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - with: - script: | - const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); - await determineAutomaticLockdown(github, context, core); + GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }} + GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} + run: bash ${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh - name: Download container images - run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.0 ghcr.io/github/gh-aw-firewall/squid:0.25.0 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_1b5f35ab740ec175_EOF' {"add_comment":{"hide_older_comments":true,"max":10,"target":"*"},"add_labels":{"allowed":["AI-thinks-issue-fixed","AI-thinks-windows-only"],"max":30,"target":"*"},"create_issue":{"labels":["automation","repo-assist"],"max":4,"title_prefix":"[Repo Assist] "},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":10240,"max_patch_size":10240}]},"update_issue":{"allow_body":true,"max":1,"target":"*","title_prefix":"[Repo Assist] "}} - GH_AW_SAFE_OUTPUTS_CONFIG_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_1b5f35ab740ec175_EOF - name: Write Safe Outputs Tools run: | - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_a46ff0c1b20be7a8_EOF' { "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *.", @@ -467,8 +463,8 @@ jobs: "repo_params": {}, "dynamic_tools": [] } - GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' + GH_AW_SAFE_OUTPUTS_TOOLS_META_a46ff0c1b20be7a8_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_db806f7f6689b41b_EOF' { "add_comment": { "defaultMax": 1, @@ -652,7 +648,7 @@ jobs: "customValidation": "requiresOneOf:status,title,body" } } - GH_AW_SAFE_OUTPUTS_VALIDATION_EOF + GH_AW_SAFE_OUTPUTS_VALIDATION_db806f7f6689b41b_EOF node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs - name: Generate Safe Outputs MCP Server Config id: safe-outputs-config @@ -698,8 +694,6 @@ jobs: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} - GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} run: | set -eo pipefail @@ -720,7 +714,7 @@ jobs: export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + cat << GH_AW_MCP_CONFIG_63fbaf7b58f9c92e_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh { "mcpServers": { "github": { @@ -734,8 +728,10 @@ jobs: }, "guard-policies": { "allow-only": { - "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", - "repos": "$GITHUB_MCP_GUARD_REPOS" + "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }}, + "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }}, + "min-integrity": "none", + "repos": "all" } } }, @@ -761,7 +757,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_EOF + GH_AW_MCP_CONFIG_63fbaf7b58f9c92e_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -778,8 +774,8 @@ jobs: set -o pipefail touch /tmp/gh-aw/agent-step-summary.md # shellcheck disable=SC1003 - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --allow-domains "*.pythonhosted.org,*.vsblob.vsassets.io,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains '*.pythonhosted.org,*.vsblob.vsassets.io,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} @@ -788,7 +784,7 @@ jobs: GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.64.0 + GH_AW_VERSION: v0.64.2 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -947,6 +943,8 @@ jobs: /tmp/gh-aw/sandbox/agent/logs/ /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/proxy-logs/ + !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ /tmp/gh-aw/safeoutputs.jsonl @@ -987,7 +985,7 @@ jobs: total_count: ${{ steps.missing_tool.outputs.total_count }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -1112,7 +1110,7 @@ jobs: detection_success: ${{ steps.detection_conclusion.outputs.success }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -1131,7 +1129,7 @@ jobs: echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" # --- Threat Detection --- - name: Download container images - run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.0 ghcr.io/github/gh-aw-firewall/squid:0.25.0 + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 - name: Check if detection needed id: detection_guard if: always() @@ -1186,32 +1184,25 @@ jobs: env: GH_HOST: github.com - name: Install AWF binary - run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.0 + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' id: detection_agentic_execution # Copilot CLI tool arguments (sorted): - # --allow-tool shell(cat) - # --allow-tool shell(grep) - # --allow-tool shell(head) - # --allow-tool shell(jq) - # --allow-tool shell(ls) - # --allow-tool shell(tail) - # --allow-tool shell(wc) timeout-minutes: 20 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md # shellcheck disable=SC1003 - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: gpt-5.1-codex-mini + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.64.0 + GH_AW_VERSION: v0.64.2 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -1252,14 +1243,14 @@ jobs: matched_command: ${{ steps.check_command_position.outputs.matched_command }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Check team membership for command workflow id: check_membership uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: - GH_AW_REQUIRED_ROLES: admin,maintainer,write + GH_AW_REQUIRED_ROLES: "admin,maintainer,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -1296,7 +1287,7 @@ jobs: validation_failed_default: ${{ steps.push_repo_memory_default.outputs.validation_failed }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Checkout repository @@ -1378,7 +1369,7 @@ jobs: process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@51c65948c64ab6752536ead71fba1fc2c20ed0bc # v0.64.0 + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -1403,7 +1394,7 @@ jobs: # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. GH_HOST="${GITHUB_SERVER_URL#https://}" GH_HOST="${GH_HOST#http://}" - echo "GH_HOST=${GH_HOST}" >> "$GITHUB_OUTPUT" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - name: Process Safe Outputs id: process_safe_outputs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 diff --git a/.github/workflows/repo-assist.md b/.github/workflows/repo-assist.md index ce426b23965..6e6fac0c173 100644 --- a/.github/workflows/repo-assist.md +++ b/.github/workflows/repo-assist.md @@ -66,6 +66,7 @@ tools: web-fetch: github: toolsets: [all] + min-integrity: none bash: true repo-memory: true From 47ffe53e468f48b7eb1bea36e28cb71705046050 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 30 Mar 2026 12:24:32 +0200 Subject: [PATCH 05/19] Add Regression PR Shepherd workflow (#19500) * Add Regression PR Shepherd agentic workflow Shepherds open AI-Issue-Regression-PR pull requests to completion: - Fixes CI failures and addresses review feedback - Detects when a test proves the bug still exists (removes label, tags maintainers) - Runs 6x/day, only touches tests/ files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add min-integrity: none * Add min-integrity: none Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../workflows/regression-pr-shepherd.lock.yml | 1227 +++++++++++++++++ .github/workflows/regression-pr-shepherd.md | 145 ++ 2 files changed, 1372 insertions(+) create mode 100644 .github/workflows/regression-pr-shepherd.lock.yml create mode 100644 .github/workflows/regression-pr-shepherd.md diff --git a/.github/workflows/regression-pr-shepherd.lock.yml b/.github/workflows/regression-pr-shepherd.lock.yml new file mode 100644 index 00000000000..92b9aba5bf5 --- /dev/null +++ b/.github/workflows/regression-pr-shepherd.lock.yml @@ -0,0 +1,1227 @@ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ +# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ +# +# This file was automatically generated by gh-aw (v0.64.2). DO NOT EDIT. +# +# To update this file, edit the corresponding .md file and run: +# gh aw compile +# Not all edits will cause changes to this file. +# +# For more information: https://github.github.com/gh-aw/introduction/overview/ +# +# Shepherds open regression test PRs (AI-Issue-Regression-PR label) to completion. +# Fixes CI failures, addresses review feedback, and detects when a "regression test" +# actually proves the bug still exists. +# Runs 6 times per day. +# +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"83657c4bc08a81d82e8fbf14c41ebe0e941dcd4c5984fe0b5501193e58921dd6","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot"} + +name: "Regression PR Shepherd" +"on": + schedule: + - cron: "54 */4 * * *" + # Friendly format: every 4h (scattered) + workflow_dispatch: + inputs: + aw_context: + default: "" + description: Agent caller context (used internally by Agentic Workflows). + required: false + type: string + +permissions: {} + +concurrency: + group: "gh-aw-${{ github.workflow }}" + +run-name: "Regression PR Shepherd" + +jobs: + activation: + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + comment_id: "" + comment_repo: "" + lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} + model: ${{ steps.generate_aw_info.outputs.model }} + secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Generate agentic run info + id: generate_aw_info + env: + GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} + GH_AW_INFO_VERSION: "latest" + GH_AW_INFO_AGENT_VERSION: "latest" + GH_AW_INFO_CLI_VERSION: "v0.64.2" + GH_AW_INFO_WORKFLOW_NAME: "Regression PR Shepherd" + GH_AW_INFO_EXPERIMENTAL: "false" + GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" + GH_AW_INFO_STAGED: "false" + GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet"]' + GH_AW_INFO_FIREWALL_ENABLED: "true" + GH_AW_INFO_AWF_VERSION: "v0.25.1" + GH_AW_INFO_AWMG_VERSION: "" + GH_AW_INFO_FIREWALL_TYPE: "squid" + GH_AW_COMPILED_STRICT: "true" + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); + await main(core, context); + - name: Validate COPILOT_GITHUB_TOKEN secret + id: validate-secret + run: ${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + - name: Checkout .github and .agents folders + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + sparse-checkout: | + .github + .agents + sparse-checkout-cone-mode: true + fetch-depth: 1 + - name: Check workflow file timestamps + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_WORKFLOW_FILE: "regression-pr-shepherd.lock.yml" + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + await main(); + - name: Create prompt with built-in context + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_WIKI_NOTE: ${{ '' }} + # poutine:ignore untrusted_checkout_exec + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh + { + cat << 'GH_AW_PROMPT_25b0cc8c3d11c822_EOF' + + GH_AW_PROMPT_25b0cc8c3d11c822_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/repo_memory_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_25b0cc8c3d11c822_EOF' + + Tools: add_comment(max:5), remove_labels(max:5), push_to_pull_request_branch(max:10), missing_tool, missing_data, noop + GH_AW_PROMPT_25b0cc8c3d11c822_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" + cat << 'GH_AW_PROMPT_25b0cc8c3d11c822_EOF' + + + The following GitHub context information is available for this workflow: + {{#if __GH_AW_GITHUB_ACTOR__ }} + - **actor**: __GH_AW_GITHUB_ACTOR__ + {{/if}} + {{#if __GH_AW_GITHUB_REPOSITORY__ }} + - **repository**: __GH_AW_GITHUB_REPOSITORY__ + {{/if}} + {{#if __GH_AW_GITHUB_WORKSPACE__ }} + - **workspace**: __GH_AW_GITHUB_WORKSPACE__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} + - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} + - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} + - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} + - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{/if}} + {{#if __GH_AW_GITHUB_RUN_ID__ }} + - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ + {{/if}} + + + GH_AW_PROMPT_25b0cc8c3d11c822_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" + cat << 'GH_AW_PROMPT_25b0cc8c3d11c822_EOF' + + GH_AW_PROMPT_25b0cc8c3d11c822_EOF + cat << 'GH_AW_PROMPT_25b0cc8c3d11c822_EOF' + {{#runtime-import .github/workflows/regression-pr-shepherd.md}} + GH_AW_PROMPT_25b0cc8c3d11c822_EOF + } > "$GH_AW_PROMPT" + - name: Interpolate variables and render templates + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); + await main(); + - name: Substitute placeholders + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_MEMORY_BRANCH_NAME: 'memory/regression-pr-shepherd' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Max File Size**: 10240 bytes (0.01 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" + GH_AW_MEMORY_DESCRIPTION: '' + GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' + GH_AW_MEMORY_TARGET_REPO: ' of the current repository' + GH_AW_WIKI_NOTE: '' + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + + const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); + + // Call the substitution function + return await substitutePlaceholders({ + file: process.env.GH_AW_PROMPT, + substitutions: { + GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, + GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, + GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, + GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, + GH_AW_MEMORY_BRANCH_NAME: process.env.GH_AW_MEMORY_BRANCH_NAME, + GH_AW_MEMORY_CONSTRAINTS: process.env.GH_AW_MEMORY_CONSTRAINTS, + GH_AW_MEMORY_DESCRIPTION: process.env.GH_AW_MEMORY_DESCRIPTION, + GH_AW_MEMORY_DIR: process.env.GH_AW_MEMORY_DIR, + GH_AW_MEMORY_TARGET_REPO: process.env.GH_AW_MEMORY_TARGET_REPO, + GH_AW_WIKI_NOTE: process.env.GH_AW_WIKI_NOTE + } + }); + - name: Validate prompt placeholders + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + # poutine:ignore untrusted_checkout_exec + run: bash ${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh + - name: Print prompt + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + # poutine:ignore untrusted_checkout_exec + run: bash ${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh + - name: Upload activation artifact + if: success() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: activation + path: | + /tmp/gh-aw/aw_info.json + /tmp/gh-aw/aw-prompts/prompt.txt + retention-days: 1 + + agent: + needs: activation + runs-on: ubuntu-latest + permissions: read-all + concurrency: + group: "gh-aw-copilot-${{ github.workflow }}" + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GH_AW_ASSETS_ALLOWED_EXTS: "" + GH_AW_ASSETS_BRANCH: "" + GH_AW_ASSETS_MAX_SIZE_KB: 0 + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_WORKFLOW_ID_SANITIZED: regressionprshepherd + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} + model: ${{ needs.activation.outputs.model }} + output: ${{ steps.collect_output.outputs.output }} + output_types: ${{ steps.collect_output.outputs.output_types }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Set runtime paths + id: set-runtime-paths + run: | + echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" >> "$GITHUB_OUTPUT" + echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" >> "$GITHUB_OUTPUT" + echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" >> "$GITHUB_OUTPUT" + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Create gh-aw temp directory + run: bash ${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh + - name: Configure gh CLI for GitHub Enterprise + run: bash ${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh + env: + GH_TOKEN: ${{ github.token }} + # Repo memory git-based storage configuration from frontmatter processed below + - name: Clone repo-memory branch (default) + env: + GH_TOKEN: ${{ github.token }} + GITHUB_SERVER_URL: ${{ github.server_url }} + BRANCH_NAME: memory/regression-pr-shepherd + TARGET_REPO: ${{ github.repository }} + MEMORY_DIR: /tmp/gh-aw/repo-memory/default + CREATE_ORPHAN: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/clone_repo_memory_branch.sh + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Checkout PR branch + id: checkout-pr + if: | + github.event.pull_request || github.event.issue.pull_request + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); + await main(); + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + - name: Parse integrity filter lists + id: parse-guard-vars + env: + GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }} + GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} + run: bash ${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + - name: Write Safe Outputs Config + run: | + mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_a55f8beea3f2fc07_EOF' + {"add_comment":{"hide_older_comments":true,"max":5,"target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":10240,"max_patch_size":10240}]},"push_to_pull_request_branch":{"if_no_changes":"warn","labels":["AI-Issue-Regression-PR"],"max":10,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_path_prefixes":[".github/",".agents/"],"target":"*","title_prefix":"Add regression test: "},"remove_labels":{"allowed":["AI-thinks-issue-fixed"],"max":5,"target":"*"}} + GH_AW_SAFE_OUTPUTS_CONFIG_a55f8beea3f2fc07_EOF + - name: Write Safe Outputs Tools + run: | + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_3c79f70a237ce57c_EOF' + { + "description_suffixes": { + "add_comment": " CONSTRAINTS: Maximum 5 comment(s) can be added. Target: *.", + "push_to_pull_request_branch": " CONSTRAINTS: Maximum 10 push(es) can be made. The target pull request title must start with \"Add regression test: \".", + "remove_labels": " CONSTRAINTS: Maximum 5 label(s) can be removed. Only these labels can be removed: [AI-thinks-issue-fixed]. Target: *." + }, + "repo_params": {}, + "dynamic_tools": [] + } + GH_AW_SAFE_OUTPUTS_TOOLS_META_3c79f70a237ce57c_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_d170437643d09800_EOF' + { + "add_comment": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "item_number": { + "issueOrPRNumber": true + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, + "missing_data": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "context": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "data_type": { + "type": "string", + "sanitize": true, + "maxLength": 128 + }, + "reason": { + "type": "string", + "sanitize": true, + "maxLength": 256 + } + } + }, + "missing_tool": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 512 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "tool": { + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "noop": { + "defaultMax": 1, + "fields": { + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + } + } + }, + "push_to_pull_request_branch": { + "defaultMax": 1, + "fields": { + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "pull_request_number": { + "issueOrPRNumber": true + } + } + }, + "remove_labels": { + "defaultMax": 5, + "fields": { + "item_number": { + "issueNumberOrTemporaryId": true + }, + "labels": { + "required": true, + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + } + } + GH_AW_SAFE_OUTPUTS_VALIDATION_d170437643d09800_EOF + node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs + - name: Generate Safe Outputs MCP Server Config + id: safe-outputs-config + run: | + # Generate a secure random API key (360 bits of entropy, 40+ chars) + # Mask immediately to prevent timing vulnerabilities + API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${API_KEY}" + + PORT=3001 + + # Set outputs for next steps + { + echo "safe_outputs_api_key=${API_KEY}" + echo "safe_outputs_port=${PORT}" + } >> "$GITHUB_OUTPUT" + + echo "Safe Outputs MCP server will run on port ${PORT}" + + - name: Start Safe Outputs MCP HTTP Server + id: safe-outputs-start + env: + DEBUG: '*' + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + run: | + # Environment variables are set above to prevent template injection + export DEBUG + export GH_AW_SAFE_OUTPUTS_PORT + export GH_AW_SAFE_OUTPUTS_API_KEY + export GH_AW_SAFE_OUTPUTS_TOOLS_PATH + export GH_AW_SAFE_OUTPUTS_CONFIG_PATH + export GH_AW_MCP_LOG_DIR + + bash ${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh + + - name: Start MCP Gateway + id: start-mcp-gateway + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + set -eo pipefail + mkdir -p /tmp/gh-aw/mcp-config + + # Export gateway environment variables for MCP config and gateway script + export MCP_GATEWAY_PORT="80" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_API_KEY}" + export MCP_GATEWAY_API_KEY + export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" + mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" + export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export DEBUG="*" + + export GH_AW_ENGINE="copilot" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' + + mkdir -p /home/runner/.copilot + cat << GH_AW_MCP_CONFIG_a0f4ea742639b7d6_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + { + "mcpServers": { + "github": { + "type": "stdio", + "container": "ghcr.io/github/github-mcp-server:v0.32.0", + "env": { + "GITHUB_HOST": "\${GITHUB_SERVER_URL}", + "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_READ_ONLY": "1", + "GITHUB_TOOLSETS": "all" + }, + "guard-policies": { + "allow-only": { + "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }}, + "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }}, + "min-integrity": "none", + "repos": "all" + } + } + }, + "safeoutputs": { + "type": "http", + "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", + "headers": { + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + }, + "guard-policies": { + "write-sink": { + "accept": [ + "*" + ] + } + } + } + }, + "gateway": { + "port": $MCP_GATEWAY_PORT, + "domain": "${MCP_GATEWAY_DOMAIN}", + "apiKey": "${MCP_GATEWAY_API_KEY}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + } + } + GH_AW_MCP_CONFIG_a0f4ea742639b7d6_EOF + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw + - name: Clean git credentials + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh + - name: Execute GitHub Copilot CLI + id: agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 30 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains '*.vsblob.vsassets.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json + GH_AW_PHASE: agent + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_VERSION: v0.64.2 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/detect_inference_access_error.sh + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Copy Copilot session state files to logs + if: always() + continue-on-error: true + run: | + # Copy Copilot session state files to logs folder for artifact collection + # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them + SESSION_STATE_DIR="$HOME/.copilot/session-state" + LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" + + if [ -d "$SESSION_STATE_DIR" ]; then + echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" + mkdir -p "$LOGS_DIR" + cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true + echo "Session state files copied successfully" + else + echo "No session-state directory found at $SESSION_STATE_DIR" + fi + - name: Stop MCP Gateway + if: always() + continue-on-error: true + env: + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" + - name: Redact secrets in logs + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); + await main(); + env: + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Append agent step summary + if: always() + run: bash ${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh + - name: Copy Safe Outputs + if: always() + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + run: | + mkdir -p /tmp/gh-aw + cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true + - name: Ingest agent output + id: collect_output + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_ALLOWED_DOMAINS: "*.vsblob.vsassets.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); + await main(); + - name: Parse agent logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + await main(); + - name: Parse MCP Gateway logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); + await main(); + - name: Print firewall logs + if: always() + continue-on-error: true + env: + AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs + run: | + # Fix permissions on firewall logs so they can be uploaded as artifacts + # AWF runs with sudo, creating files owned by root + sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true + # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) + if command -v awf &> /dev/null; then + awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" + else + echo 'AWF binary not installed, skipping firewall log summary' + fi + - name: Write agent output placeholder if missing + if: always() + run: | + if [ ! -f /tmp/gh-aw/agent_output.json ]; then + echo '{"items":[]}' > /tmp/gh-aw/agent_output.json + fi + # Upload repo memory as artifacts for push job + - name: Upload repo-memory artifact (default) + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: repo-memory-default + path: /tmp/gh-aw/repo-memory/default + retention-days: 1 + if-no-files-found: ignore + - name: Upload agent artifacts + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: agent + path: | + /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/sandbox/agent/logs/ + /tmp/gh-aw/redacted-urls.log + /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/proxy-logs/ + !/tmp/gh-aw/proxy-logs/proxy-tls/ + /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/agent/ + /tmp/gh-aw/safeoutputs.jsonl + /tmp/gh-aw/agent_output.json + /tmp/gh-aw/aw-*.patch + if-no-files-found: ignore + - name: Upload firewall audit logs + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: firewall-audit-logs + path: | + /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/sandbox/firewall/audit/ + if-no-files-found: ignore + + conclusion: + needs: + - activation + - agent + - detection + - push_repo_memory + - safe_outputs + if: always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true') + runs-on: ubuntu-slim + permissions: + contents: write + discussions: write + issues: write + pull-requests: write + concurrency: + group: "gh-aw-conclusion-regression-pr-shepherd" + cancel-in-progress: false + outputs: + noop_message: ${{ steps.noop.outputs.noop_message }} + tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} + total_count: ${{ steps.missing_tool.outputs.total_count }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Process No-Op Messages + id: noop + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_NOOP_MAX: "1" + GH_AW_WORKFLOW_NAME: "Regression PR Shepherd" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/noop.cjs'); + await main(); + - name: Record Missing Tool + id: missing_tool + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Regression PR Shepherd" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + await main(); + - name: Handle Agent Failure + id: handle_agent_failure + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Regression PR Shepherd" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_WORKFLOW_ID: "regression-pr-shepherd" + GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} + GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} + GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} + GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_PUSH_REPO_MEMORY_RESULT: ${{ needs.push_repo_memory.result }} + GH_AW_REPO_MEMORY_VALIDATION_FAILED_default: ${{ needs.push_repo_memory.outputs.validation_failed_default }} + GH_AW_REPO_MEMORY_VALIDATION_ERROR_default: ${{ needs.push_repo_memory.outputs.validation_error_default }} + GH_AW_REPO_MEMORY_PATCH_SIZE_EXCEEDED_default: ${{ needs.push_repo_memory.outputs.patch_size_exceeded_default }} + GH_AW_GROUP_REPORTS: "false" + GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_TIMEOUT_MINUTES: "30" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + await main(); + - name: Handle No-Op Message + id: handle_noop_message + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Regression PR Shepherd" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} + GH_AW_NOOP_REPORT_AS_ISSUE: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + await main(); + + detection: + needs: agent + if: always() && needs.agent.result != 'skipped' + runs-on: ubuntu-latest + outputs: + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + # --- Threat Detection --- + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Regression PR Shepherd" + WORKFLOW_DESCRIPTION: "Shepherds open regression test PRs (AI-Issue-Regression-PR label) to completion.\nFixes CI failures, addresses review feedback, and detects when a \"regression test\"\nactually proves the bug still exists.\nRuns 6 times per day." + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); + await main(); + - name: Ensure threat-detection directory and log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 20 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + GH_AW_PHASE: detection + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_VERSION: v0.64.2 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Upload threat detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: detection + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Parse and conclude threat detection + id: detection_conclusion + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + + push_repo_memory: + needs: + - agent + - detection + if: always() && needs.detection.result == 'success' + runs-on: ubuntu-latest + permissions: + contents: write + concurrency: + group: "push-repo-memory-${{ github.repository }}" + cancel-in-progress: false + outputs: + patch_size_exceeded_default: ${{ steps.push_repo_memory_default.outputs.patch_size_exceeded }} + validation_error_default: ${{ steps.push_repo_memory_default.outputs.validation_error }} + validation_failed_default: ${{ steps.push_repo_memory_default.outputs.validation_failed }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + sparse-checkout: . + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Download repo-memory artifact (default) + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + continue-on-error: true + with: + name: repo-memory-default + path: /tmp/gh-aw/repo-memory/default + - name: Push repo-memory changes (default) + id: push_repo_memory_default + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ github.token }} + GITHUB_RUN_ID: ${{ github.run_id }} + GITHUB_SERVER_URL: ${{ github.server_url }} + ARTIFACT_DIR: /tmp/gh-aw/repo-memory/default + MEMORY_ID: default + TARGET_REPO: ${{ github.repository }} + BRANCH_NAME: memory/regression-pr-shepherd + MAX_FILE_SIZE: 10240 + MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 + ALLOWED_EXTENSIONS: '[]' + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/push_repo_memory.cjs'); + await main(); + + safe_outputs: + needs: + - activation + - agent + - detection + if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success' + runs-on: ubuntu-slim + permissions: + contents: write + discussions: write + issues: write + pull-requests: write + timeout-minutes: 15 + env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/regression-pr-shepherd" + GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} + GH_AW_WORKFLOW_ID: "regression-pr-shepherd" + GH_AW_WORKFLOW_NAME: "Regression PR Shepherd" + outputs: + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }} + comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }} + create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} + create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} + process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }} + push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Checkout repository + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }} + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + persist-credentials: false + fetch-depth: 1 + - name: Configure Git credentials + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Configure GH_HOST for enterprise compatibility + id: ghes-host-config + shell: bash + run: | + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" + - name: Process Safe Outputs + id: process_safe_outputs + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ALLOWED_DOMAINS: "*.vsblob.vsassets.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":5,\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"labels\":[\"AI-Issue-Regression-PR\"],\"max\":10,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"target\":\"*\",\"title_prefix\":\"Add regression test: \"},\"remove_labels\":{\"allowed\":[\"AI-thinks-issue-fixed\"],\"max\":5,\"target\":\"*\"}}" + GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); + await main(); + - name: Upload Safe Output Items + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: safe-output-items + path: /tmp/gh-aw/safe-output-items.jsonl + if-no-files-found: ignore + diff --git a/.github/workflows/regression-pr-shepherd.md b/.github/workflows/regression-pr-shepherd.md new file mode 100644 index 00000000000..1585ed62804 --- /dev/null +++ b/.github/workflows/regression-pr-shepherd.md @@ -0,0 +1,145 @@ +--- +description: | + Shepherds open regression test PRs (AI-Issue-Regression-PR label) to completion. + Fixes CI failures, addresses review feedback, and detects when a "regression test" + actually proves the bug still exists. + Runs 6 times per day. + +on: + schedule: every 4h + workflow_dispatch: + +timeout-minutes: 30 + +permissions: read-all + +network: + allowed: + - defaults + - dotnet + +safe-outputs: + add-comment: + max: 5 + target: "*" + hide-older-comments: true + push-to-pull-request-branch: + target: "*" + title-prefix: "Add regression test: " + labels: [AI-Issue-Regression-PR] + max: 10 + remove-labels: + allowed: ["AI-thinks-issue-fixed"] + max: 5 + target: "*" + +tools: + github: + toolsets: [all] + min-integrity: none + bash: true + repo-memory: true +--- + +# Regression PR Shepherd + +You shepherd open regression test PRs to completion. These PRs add tests for issues labeled `AI-thinks-issue-fixed`. They should be simple — only touching files under `tests/` or `vsintegration/tests/`. + +## Principles + +- **Fix forward**: CI failures and review feedback should be addressed, not ignored. +- **Honesty over ego**: If the test proves the bug still exists, say so clearly. +- **Zero context assumption**: When summoning maintainers, explain everything from scratch — they haven't read the PR or issue recently. +- **One comment per PR per run**: Never post multiple comments on the same PR in a single run. + +## Process + +### Step 1 — Gather open PRs + +List all open PRs with the `AI-Issue-Regression-PR` label: +```bash +gh pr list --label "AI-Issue-Regression-PR" --state open --json number,title,headRefName,updatedAt +``` + +For each PR, determine which category it falls into (check in this order): + +### Step 2 — Categorize each PR + +**Category A: Has unaddressed review feedback** + +Check for review comments posted since the last Repo Assist comment on this PR (look for the `🤖` marker). If new human review comments exist: + +1. Read the full PR diff, all review comments, the linked issue, and ALL issue comments +2. Understand the reviewer's point in the full context of what the issue describes +3. Make the requested change — push a fix commit to the PR branch +4. Reply to each review thread confirming the change, quoting the relevant new code + +**Category B: CI failure or merge conflict** + +Check the PR's check runs and mergeable state. + +**B0 — Merge conflict**: The PR branch is behind main and has conflicts. Since these PRs only touch test files, conflicts are typically `.fsproj` `` ordering or test file edits on the same lines. Fix by: +1. Check out the PR branch: `gh pr checkout {number}` +2. Rebase onto main: `git fetch origin main && git rebase origin/main` +3. Resolve conflicts — for `.fsproj` conflicts, keep both entries in alphabetical order. For test file conflicts, keep both tests. +4. Build the test project to verify: `dotnet build tests/{TestProject}/{TestProject}.fsproj -c Release` +5. Push the rebased branch to update the PR + +If any checks failed: + +1. Fetch the failed job logs +2. Analyze the failure + + **B1 — Infrastructure/flaky failure** (unrelated to the test): Retry by pushing an empty commit or re-running the workflow. + + **B2 — Test compilation or setup error** (e.g., missing ``, wrong namespace, syntax error): Fix the test code, push the fix. + + **B3 — The added test itself fails, reproducing the original bug**: This means the issue is **NOT fixed**. The `AI-thinks-issue-fixed` label was wrong. Do ALL of the following: + - Remove the `AI-thinks-issue-fixed` label from the linked issue + - Comment on the linked issue — **brief and apologetic**, this comment will live on the issue permanently: + ``` + 🤖 Issue still reproduces. Regression test in #NNNN (PR) confirms it. Still errors with: `{one-line error summary}`. Apologies for the incorrect label. + ``` + - Comment on the PR tagging `@T-Gro` and `@abonie` — **this is where the full context goes**. Assume they have zero context: + ``` + 🤖 *This is an automated response from Regression PR Shepherd.* + + This regression test proves the bug in #{issue} still exists. Closing this PR. + + **The bug**: {one-paragraph description from issue body + comments} + + **The test**: {what the test does, link to the test code} + + **The failure**: + ``` + {exact error output} + ``` + + The `AI-thinks-issue-fixed` label has been removed from #{issue}. + cc @T-Gro @abonie + ``` + - Close the PR + + **B4 — Other test failures** (not the added test): Check if these are known flaky tests. If unrelated to the PR's changes, note this in a comment and re-trigger CI. + +**Category C: No feedback, CI passing or still running** + +Do nothing. The PR is healthy. + +### Step 3 — Avoid duplicate work + +Before pushing any fix: +- Check if you already pushed a fix for the same review comment or CI failure (compare your last commit message against the feedback) +- If the last commit on the PR is from Repo Assist and no new human feedback or CI results appeared since, skip this PR + +### Step 4 — Update memory + +Track which PRs you've processed and the last review comment timestamp you addressed, so the next run only processes new feedback. + +## Guidelines + +- **Never modify files outside `tests/` or `vsintegration/tests/`** — if a fix requires changing `src/`, that's beyond scope. Comment explaining this and tag maintainers. +- **Only comment on PRs with the `AI-Issue-Regression-PR` label or their linked issues** — never comment on any other issue or PR in the repository. If you need to tag maintainers about a bug that still exists, comment on the linked issue only. +- Begin every comment with: `🤖 *This is an automated response from Regression PR Shepherd.*` +- When fixing review feedback, keep changes minimal — address exactly what was requested. +- When a test failure reveals a real bug (Category B3), be thorough and precise in the explanation. This is the most important thing you do. From 4cf434edb114d3de7b8383c103225390c5b0b995 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 30 Mar 2026 12:26:46 +0200 Subject: [PATCH 06/19] Improve repo-assist: regression test verification, windows-only revisit, stricter labeling (#19499) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable create-pull-request and push-to-pull-request-branch for regression test PRs - Enable remove-labels for AI-thinks-issue-fixed and AI-thinks-windows-only - Add Task 2: Regression Test Verification with adversarial dispute step - Add Task 3: Systematic revisit of AI-thinks-windows-only claims - Reorder tasks: Task 1 → Task 3 → Task 2 → FINAL (Task 3 feeds into Task 2) - Strict windows-only rules with explicit FCS-testable feature list - Fix memory section to match actual state.json schema - Remove close-issue actions (closure happens via PR merge with Fixes link) - Fix stale references, contradictory instructions, date cutoff to 2024 - Clarify anti-spam rules for multi-task commenting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .github/workflows/repo-assist.lock.yml | 142 ++++++++++++++- .github/workflows/repo-assist.md | 240 +++++++++++++++++++++---- 2 files changed, 344 insertions(+), 38 deletions(-) diff --git a/.github/workflows/repo-assist.lock.yml b/.github/workflows/repo-assist.lock.yml index e28af9c044b..06789634de0 100644 --- a/.github/workflows/repo-assist.lock.yml +++ b/.github/workflows/repo-assist.lock.yml @@ -222,7 +222,11 @@ jobs: cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' - Tools: add_comment(max:10), create_issue(max:4), update_issue, add_labels(max:30), missing_tool, missing_data, noop + Tools: add_comment(max:10), create_issue(max:4), update_issue, create_pull_request(max:10), add_labels(max:30), remove_labels(max:10), push_to_pull_request_branch(max:10), missing_tool, missing_data, noop + GH_AW_PROMPT_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" + cat << 'GH_AW_PROMPT_EOF' The following GitHub context information is available for this workflow: @@ -458,6 +462,9 @@ jobs: "add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *.", "add_labels": " CONSTRAINTS: Maximum 30 label(s) can be added. Only these labels are allowed: [\"AI-thinks-issue-fixed\" \"AI-thinks-windows-only\"]. Target: *.", "create_issue": " CONSTRAINTS: Maximum 4 issue(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [\"automation\" \"repo-assist\"] will be automatically added.", + "create_pull_request": " CONSTRAINTS: Maximum 10 pull request(s) can be created. Title will be prefixed with \"Add regression test: \". Labels [\"NO_RELEASE_NOTES\" \"AI-Issue-Regression-PR\"] will be automatically added. Reviewers [\"abonie\" \"T-Gro\"] will be assigned.", + "push_to_pull_request_branch": " CONSTRAINTS: Maximum 10 push(es) can be made. The target pull request title must start with \"Add regression test: \".", + "remove_labels": " CONSTRAINTS: Maximum 10 label(s) can be removed. Only these labels can be removed: [AI-thinks-issue-fixed AI-thinks-windows-only]. Target: *.", "update_issue": " CONSTRAINTS: Maximum 1 issue(s) can be updated. Target: *. The target issue title must start with \"[Repo Assist] \"." }, "repo_params": {}, @@ -536,6 +543,42 @@ jobs: } } }, + "create_pull_request": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "draft": { + "type": "boolean" + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "repo": { + "type": "string", + "maxLength": 256 + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, "missing_data": { "defaultMax": 20, "fields": { @@ -593,6 +636,45 @@ jobs: } } }, + "push_to_pull_request_branch": { + "defaultMax": 1, + "fields": { + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "pull_request_number": { + "issueOrPRNumber": true + } + } + }, + "remove_labels": { + "defaultMax": 5, + "fields": { + "item_number": { + "issueNumberOrTemporaryId": true + }, + "labels": { + "required": true, + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, "update_issue": { "defaultMax": 1, "fields": { @@ -972,7 +1054,7 @@ jobs: if: always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true') runs-on: ubuntu-slim permissions: - contents: read + contents: write discussions: write issues: write pull-requests: write @@ -1048,6 +1130,8 @@ jobs: GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} + GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} + GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} GH_AW_PUSH_REPO_MEMORY_RESULT: ${{ needs.push_repo_memory.result }} GH_AW_REPO_MEMORY_VALIDATION_FAILED_default: ${{ needs.push_repo_memory.outputs.validation_failed_default }} @@ -1082,6 +1166,22 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); await main(); + - name: Handle Create Pull Request Error + id: handle_create_pr_error + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Repo Assist" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9135cdfde26838a01779aa966628308404ec1f02/workflows/repo-assist.md" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_create_pr_error.cjs'); + await main(); - name: Update reaction comment with completion status id: conclusion uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -1338,12 +1438,13 @@ jobs: safe_outputs: needs: + - activation - agent - detection if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success' runs-on: ubuntu-slim permissions: - contents: read + contents: write discussions: write issues: write pull-requests: write @@ -1365,8 +1466,12 @@ jobs: create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }} created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }} + created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }} + created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }} process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }} + push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} steps: - name: Setup Scripts uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 @@ -1386,6 +1491,34 @@ jobs: mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Checkout repository + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }} + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + persist-credentials: false + fetch-depth: 1 + - name: Configure Git credentials + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Configure GH_HOST for enterprise compatibility id: ghes-host-config shell: bash @@ -1403,7 +1536,8 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.pythonhosted.org,*.vsblob.vsassets.io,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":10,\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"AI-thinks-issue-fixed\",\"AI-thinks-windows-only\"],\"max\":30,\"target\":\"*\"},\"create_issue\":{\"labels\":[\"automation\",\"repo-assist\"],\"max\":4,\"title_prefix\":\"[Repo Assist] \"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"update_issue\":{\"allow_body\":true,\"max\":1,\"target\":\"*\",\"title_prefix\":\"[Repo Assist] \"}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":10,\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"AI-thinks-issue-fixed\",\"AI-thinks-windows-only\"],\"max\":30,\"target\":\"*\"},\"create_issue\":{\"labels\":[\"automation\",\"repo-assist\"],\"max\":4,\"title_prefix\":\"[Repo Assist] \"},\"create_pull_request\":{\"allowed_files\":[\"tests/**\",\"vsintegration/tests/**\"],\"auto_merge\":true,\"draft\":false,\"labels\":[\"NO_RELEASE_NOTES\",\"AI-Issue-Regression-PR\"],\"max\":10,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"reviewers\":[\"abonie\",\"T-Gro\"],\"title_prefix\":\"Add regression test: \"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"labels\":[\"AI-Issue-Regression-PR\"],\"max\":10,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"target\":\"*\",\"title_prefix\":\"Add regression test: \"},\"remove_labels\":{\"allowed\":[\"AI-thinks-issue-fixed\",\"AI-thinks-windows-only\"],\"max\":10,\"target\":\"*\"},\"update_issue\":{\"allow_body\":true,\"max\":1,\"target\":\"*\",\"title_prefix\":\"[Repo Assist] \"}}" + GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/repo-assist.md b/.github/workflows/repo-assist.md index 6e6fac0c173..731b9a73b72 100644 --- a/.github/workflows/repo-assist.md +++ b/.github/workflows/repo-assist.md @@ -35,16 +35,19 @@ safe-outputs: max: 10 target: "*" hide-older-comments: true - # create-pull-request: - # draft: true - # title-prefix: "[Repo Assist] " - # labels: [automation, repo-assist] - # protected-files: fallback-to-issue - # max: 4 - # push-to-pull-request-branch: - # target: "*" - # title-prefix: "[Repo Assist] " - # max: 4 + create-pull-request: + title-prefix: "Add regression test: " + labels: [NO_RELEASE_NOTES, AI-Issue-Regression-PR] + reviewers: [abonie, T-Gro] + auto-merge: true + draft: false + allowed-files: ["tests/**", "vsintegration/tests/**"] + max: 10 + push-to-pull-request-branch: + target: "*" + title-prefix: "Add regression test: " + labels: [AI-Issue-Regression-PR] + max: 10 create-issue: title-prefix: "[Repo Assist] " labels: [automation, repo-assist] @@ -57,10 +60,10 @@ safe-outputs: allowed: ["AI-thinks-issue-fixed", "AI-thinks-windows-only"] max: 30 target: "*" - # remove-labels: - # allowed: [bug, enhancement, "help wanted", "good first issue", "spam", "off topic", documentation, question, duplicate, wontfix, "needs triage", "needs investigation", "breaking change", performance, security, refactor] - # max: 5 - # target: "*" + remove-labels: + allowed: ["AI-thinks-issue-fixed", "AI-thinks-windows-only"] + max: 10 + target: "*" tools: web-fetch: @@ -79,7 +82,7 @@ source: githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa96662 Take heed of **instructions**: "${{ steps.sanitized.outputs.text }}" -If these are non-empty (not ""), then you have been triggered via `/repo-assist `. Follow the user's instructions instead of the normal scheduled workflow. Focus exclusively on those instructions. Apply all the same guidelines (read AGENTS.md, run formatters/linters/tests, be polite, use AI disclosure). Skip the weighted task selection and Task 11 reporting, and instead directly do what the user requested. If no specific instructions were provided (empty or blank), proceed with the normal scheduled workflow below. +If these are non-empty (not ""), then you have been triggered via `/repo-assist `. Follow the user's instructions instead of the normal scheduled workflow. Focus exclusively on those instructions. Apply all the same guidelines (read AGENTS.md, run formatters/linters/tests, be polite, use AI disclosure). Skip the normal task sequence and the monthly activity summary update, and instead directly do what the user requested. If no specific instructions were provided (empty or blank), proceed with the normal scheduled workflow below. Then exit - do not run the normal workflow after completing the instructions. @@ -93,33 +96,58 @@ Always be: - **Concise**: Keep comments focused and actionable. Avoid walls of text. - **Mindful of project values**: Prioritize **stability**, **correctness**, and **minimal dependencies**. Do not introduce new dependencies without clear justification. - **Transparent about your nature**: Always clearly identify yourself as Repo Assist, an automated AI assistant. Never pretend to be a human maintainer. -- **Restrained**: When in doubt, do nothing. It is always better to stay silent than to post a redundant, unhelpful, or spammy comment. Human maintainers' attention is precious - do not waste it. +- **Restrained**: When in doubt and lacking verified evidence, do nothing. It is always better to stay silent than to post a redundant, unhelpful, or spammy comment. Human maintainers' attention is precious - do not waste it. ## Memory -Use persistent repo memory to track: +Use persistent repo memory to track. The memory is stored in `state.json` on the `memory/repo-assist` branch. + +The current schema uses these fields (extend as needed, but never remove existing fields): -- issues already commented on (with timestamps to detect new human activity) -- fix attempts and outcomes, improvement ideas already submitted, a short to-do list -- a **backlog cursor** so each run continues where the previous one left off -- a second **backlog windows-only cursor** for addressing issues that were given up too easily and labelled "AI-thinks-windows-only" too eagerly -- previously checked off items (checked off by maintainer) in the Monthly Activity Summary to maintain an accurate pending actions list for maintainers -- very concise tips and tricks for reproducing issues +```json +{ + "c": 12067, // backlog cursor — last processed issue number (ascending order) + "lr": "2026-03-26", // last run date — ISO date string + "ms": 19439, // monthly summary issue number + "woc": 5858, // windows-only revisit cursor — last processed issue number + "rtc": 6648 // regression test cursor — last processed issue number +} +``` + +Guidelines for memory evolution: +- Add new fields with short keys (2-3 chars) to keep the JSON compact +- Use issue numbers for cursors (resume from issues with number > cursor value) +- Do NOT track "issues commented on" in memory — instead, check the issue's comments directly to see if Repo Assist already commented. This is authoritative and doesn't grow unboundedly. +- The existing `cm` field is deprecated. Ignore it if present; do not add to it. Read memory at the **start** of every run; update it at the **end**. **Important**: Memory may not be 100% accurate. Issues may have been created, closed, or commented on; PRs may have been created, merged, commented on, or closed since the last run. Always verify memory against current repository state — reviewing recent activity since your last run is wise before acting on stale assumptions. -**Memory backlog tracking**: Your memory may contain notes about issues or PRs that still need attention (e.g., "issues #384, #336 have labels but no comments"). These are **action items for you**, not just informational notes. Each run, check your memory's `notes` field and other tracking fields for any explicitly flagged backlog work, and prioritise acting on it. +**Memory backlog tracking**: Before commenting on any issue, check the issue's existing comments for a Repo Assist comment (look for the `🤖` marker). To detect new human activity, compare the latest human comment timestamp against `lr`. Only re-engage if new human comments appeared after `lr`. + +## Working with Issues — Mandatory Rules + +Before taking ANY action on an issue (commenting, labeling, creating a PR), you **must** read the FULL comment history — not just the issue body. This is non-negotiable. + +1. **Read ALL comments, in order, noting timestamps and authors.** Pay special attention to human comments that appeared AFTER a previous Repo Assist comment — these may dispute, correct, or supersede the bot's analysis. + +2. **Never ignore human feedback.** If a human replied to a Repo Assist comment saying "this is wrong" or "still broken", your next action must acknowledge and address their feedback. Posting a test that ignores a human correction is worse than doing nothing. + +3. **Never loop with yourself.** If the last comment on an issue is from Repo Assist and no human has responded, do NOT post another comment. Wait for human engagement. Also, before posting, check if your new comment would convey the same information as your previous comment — if so, skip it. + +4. **Use the best available repros.** Comments often contain simplified, corrected, or additional repro steps. Use the most recent and most precise repro, not just the original issue body. If multiple distinct repro scenarios exist (e.g., issue body shows one case, a commenter shows a different triggering pattern), include all of them — each becomes a separate test case in the regression test. + +5. **If a human disputed a previous bot claim**, treat the issue as if the bot never commented. Start fresh — verify independently, and explicitly acknowledge the human's point in your new comment. ## Workflow -Each run, do Task 1 and Task FINAL +Each run, do Task 1, Task 3, Task 2, and Task FINAL (in this order — Task 3 feeds into Task 2) ### Task 1: Issue Investigation and Comment -1. List open issues sorted by creation date ascending (oldest first). Resume from your memory's backlog cursor; reset when you reach the end. **Do not assess issues posted after 1/1/2023** to avoid noise from more recent issues that haven't had time for human engagement yet. -2. **Work through "Bug" issues in reverse order, from the oldest open issue.** Read the issue comments and check memory's `comments_made` field. For every issue previously labeled as "AI-thinks-windows-only", do revisit it again and reassess. +1. List open issues sorted by creation date ascending (oldest first). Resume from issues with number > the `c` cursor. **Do not assess issues posted after 1/1/2024** to avoid noise from more recent issues that haven't had time for human engagement yet. When no more issues exist above `c` within the cutoff date, reset `c` to 0 at the end of this run — on the next run, the `lr`-based activity filter will prevent re-investigating stale issues. +2. **Work through "Bug" issues in ascending order, starting from the oldest open issue.** Read the issue comments and check if Repo Assist has already commented (look for the `🤖` marker). When the cursor has reset and you're re-scanning previously visited issues, **skip issues that have no activity (no new comments) since `lr`** — they haven't changed since you last saw them. 3. We want automatic analysis to focus on BUGS trying to identify issues that are fixed or issues that even after numerous rounds of trying hard are determined to be investigable Windows-only and labelling them. - You shall verify with fresh version of the compiler, library and tooling by following the ./build.sh script at repo root. You can build this at the start of your session, and use the same artifacts for many issues. Running tests, or even launching fsi.exe from the artifacts folder for quick repro. - Do not guess, verify. Do not ask "maintainer to verify", you verify and give high-confidence proofs about whatever you found out: @@ -128,18 +156,164 @@ Each run, do Task 1 and Task FINAL - any other findings. If the issue remains but you have some insight, write it down! - Never write "for maintainers to verify", this helps absolutely nobody. You verify, you have the tools. - For issues that are honestly asssessed to be fixed via solid reproduction steps, the label "AI-thinks-issue-fixed" should be applied and a response giving reasoning and repro if available -- For issues assess to be Windows only, the label "AI-thinks-windows-only" should be applied and no reasoning given and no comment added. However, do not be eagerly dismissive. Have a look at FSharp.Compiler.Service.Tests - the public API (consumed by VS, true) is OS agnostic. Features like autocomplete, find references, even debugging (via .pdb files) or various VS shown diagnostics - are available without visual studio. Also tooltips and parts of navigation. -- Otherwise, do nothing to avoid noise. If you don't have high confidence in a fix or in the Windows-only nature of the issue, it's better to say nothing than to risk a false positive comment or label. If you have some other high-confidence judgement about the issue, you can leave a note to the maintainer in the "Additional observations" section of the Monthly Activity Summary issue, but do not comment directly on the issue itself. If you have written solid reproduction not yet covered in the issue, write it down even if the issue still remains. This will help future implementers as an easily approachable repro case. +- **Windows-only labelling — STRICT RULES.** Do NOT label an issue `AI-thinks-windows-only` unless you have verified it is truly untestable outside Visual Studio. The following are **NOT windows-only** — they are backed by FSharp.Compiler.Service and testable on any OS: + - Semantic highlighting / classification / colorization → FCS `Tokenizer`, `Classifier` APIs + - Tooltips / QuickInfo → FCS `GetToolTip` / `GetStructuredToolTipText` + - Find all references → FCS `GetUsesOfSymbolInFile` + - Rename symbol → FCS rename logic (even if reported via VS rename UI) + - Autocomplete / IntelliSense → FCS `GetDeclarationListInfo` + - Diagnostics display / error squiggles → FCS type checking + - Code fixes and refactorings → testable via FCS APIs + - Signature generation → FCS `GetSignatureText` + - Navigation / Go to definition → FCS symbol resolution + - Debugging / breakpoints / sequence points → PDB generation, testable via IL verification + + The ONLY issues that are truly windows-only are those involving: + - VS-specific UI rendering (WPF controls, editor chrome, scroll bars, sticky scroll visual behavior) + - VS project system integration (solution explorer, project properties dialog) + - VS-specific installation / VSIX / extension loading + - VS-specific keyboard shortcuts or editor commands with no FCS equivalent + - Cross-process VS interaction (e.g., FSI output pane rendering in VS) + + If you previously labelled issues as windows-only that fall into the testable category above, you were wrong. Task 3 below will systematically revisit and correct those. + +- Otherwise, do nothing to avoid noise. If you don't have high confidence in a fix, it's better to say nothing than to risk a false positive. If you have some other high-confidence judgement, leave a note in the "Additional observations" section of the Monthly Activity Summary. If you have written a solid reproduction not yet covered in the issue, write it down — this helps future implementers. 4. Expect to engage substantively on 1–10 issues per run; you may scan many more to find good candidates. 5. Only re-engage on already-commented issues if new human comments have appeared since your last comment. 6. Begin every comment with: `🤖 *This is an automated response from Repo Assist.*` 7. Update memory with comments made and the new cursor position - and also the second cursor for "windows-only" reassessment. +### Task 2: Regression Test Verification (for every AI-thinks-issue-fixed claim) + +After Task 1 and Task 3, process every open issue that carries the `AI-thinks-issue-fixed` label (including issues that received the label during Task 1 or Task 3 in this run). For each such issue, you must produce **exactly one** of the three outcomes below. No issue may be left with the label and no verification outcome. + +#### Step A — Check for existing test coverage and PRs + +First, check if this issue has already been handled. Skip to the next issue if ANY of these are true: +1. The issue is **closed** — someone already resolved it +2. A regression test PR exists (open or merged): `gh pr list --repo dotnet/fsharp --label "AI-Issue-Regression-PR" --search "{issue_number}" --state all` +3. The issue body or comments link to a PR that addresses it +4. Repo Assist already posted a test-link comment (a comment containing a GitHub permalink to a test file) +5. Repo Assist already posted an "untestable" explanation (Outcome 3 from a previous run) +6. A human already posted a comment with test coverage or a fix reference after the `AI-thinks-issue-fixed` label was applied + +**Creating a duplicate PR or duplicate comment is a reputation-damaging mistake.** + +Then search the test suite (`tests/`) thoroughly for existing test coverage: + +1. **Easy**: `grep -r "12345\|#12345" tests/` (substituting the actual issue number) — does any test mention the issue number? +2. **Medium**: Search for the repro pattern from the issue. The test may be named differently, simplified, or part of a broader test. +3. **Hard**: Search for semantically similar setups — same language construct, same error code, same compiler area — even if naming is completely different. + +#### Step B — Dispute verification (mandatory for every candidate match) + +For every candidate test you find, you **must** reason adversarially before accepting it. Adopt the following stance and work through it explicitly: + +> "Attempt to REJECT the claim that test `{test name}` in `{file path}` adequately covers issue #{number} ({issue title}). Check: (1) Does the test SETUP reproduce the exact scenario described in the issue? (2) Do the ASSERTIONS verify the exact behavior the issue reports as broken/fixed? Both must match. If either the setup or the assertions fail to cover what the issue describes, explain precisely what is missing. Look for gaps, not confirmations." + +Only if this adversarial analysis **fails to find gaps** (i.e., confirms the test really does cover the issue) may you use Outcome 1 below. + +#### Step C — Outcomes (exactly one per issue) + +**Outcome 1: Existing test covers the issue.** + +Comment on the issue with: +- A permalink to the test source on GitHub (e.g., `https://github.com/dotnet/fsharp/blob/{commit_sha}/tests/path/File.fs#L10-L25`). GitHub automatically renders this as an embedded code snippet. Use the current HEAD commit SHA, not a branch name, so the link is permanent. +- A one-sentence explanation of why this test covers the issue + +**Outcome 2: Write a new regression test and raise a PR.** + +This is the primary expected outcome when no existing test is found. + +1. **Choose the right location.** Place the test in the semantically appropriate project, folder, and file based on the compiler feature area. **You may ONLY add or modify files under `tests/` or `vsintegration/tests/`. Never modify files under `src/`** — regression test PRs verify existing fixes, they do not implement fixes: + - Type checking / diagnostics → `tests/FSharp.Compiler.ComponentTests/ErrorMessages/` or the relevant `Conformance/` subfolder + - Code generation / IL → `tests/FSharp.Compiler.ComponentTests/EmittedIL/` + - Optimizer → `tests/FSharp.Compiler.ComponentTests/Optimize/` + - Language service (completions, tooltips, find references) → `tests/FSharp.Compiler.Service.Tests/` — **most IDE issues ARE testable on Linux** since the FSharp.Compiler.Service layer is OS-agnostic + - FSI → `tests/FSharp.Compiler.ComponentTests/Scripting/` + - Parser / syntax → `tests/FSharp.Compiler.ComponentTests/Language/` or `Conformance/` + +2. **Write the test** using the repro from the issue body AND comments (per "Working with Issues" rules — use the best available repro, which may be in a comment, not the original body). Follow the ComponentTests DSL pipeline pattern: + ```fsharp + // https://github.com/dotnet/fsharp/issues/{number} + [] + let ``Issue {number} - brief description`` () = + FSharp """ + // minimal repro from issue + """ + |> typecheck // or compile, compileExeAndRun as appropriate + |> shouldSucceed + ``` + +3. **Build and run the test** to confirm it passes: + ```bash + dotnet build tests/{TestProject}/{TestProject}.fsproj -c Release + dotnet test tests/{TestProject}/{TestProject}.fsproj -c Release --no-build -- --filter-method "*Issue {number}*" + ``` + +4. **If the test PASSES**: Before creating a PR, run the duplicate check from Step A one more time (another run may have created a PR since you last checked). Then create the PR: + - Branch: `regression-test/issue{number}` + - Title: `Add regression test: #{number}, {brief description}` + - Body: **Must** contain `Fixes https://github.com/dotnet/fsharp/issues/{number}` on its own line — this is non-negotiable. GitHub automatically closes the issue when the PR is merged. This is the ONLY mechanism for closing issues. The workflow must never close issues directly. + - Labels: `NO_RELEASE_NOTES`, `AI-Issue-Regression-PR` + - Reviewers: `abonie`, `T-Gro` + - Auto-merge: squash + - If the .fsproj needs a new `` entry, add it in alphabetical order within its section + +5. **If the test FAILS**: The issue is **not fixed**. Do all of the following: + - **Remove** the `AI-thinks-issue-fixed` label from the issue + - **Comment** on the issue with the test code, the failure output, and the conclusion that the issue remains open + - Do **not** create a PR + +**Outcome 3: Issue is genuinely untestable (expect <1% of cases).** + +Some issues cannot be verified with a test (e.g., documentation changes, IDE-specific UI rendering, installer issues). In this case: + +- Comment on the issue with a **precise, thorough explanation** of why no automated test can cover this specific issue +- Provide alternative proof of the fix (e.g., link to the commit that fixed it, screenshots, or manual verification steps you performed) +- This outcome is rare. If in doubt, the issue IS testable — IDE features like completions, tooltips, find references, diagnostics display, and navigation all work through FSharp.Compiler.Service and are testable on any OS + +#### Step D — Rate limiting and batching + +Process up to 5 issues per run. List all issues with the `AI-thinks-issue-fixed` label, ordered by issue number ascending. Skip issues with number ≤ `rtc`. After processing, set `rtc` to the highest issue number processed. Do NOT reset `rtc` to 0 — new issues that receive the label will have higher numbers and be picked up naturally. + +### Task 3: Revisit AI-thinks-windows-only Claims + +The `AI-thinks-windows-only` label was applied too eagerly in the past. Many issues labelled as windows-only are actually testable via FSharp.Compiler.Service on Linux/macOS. This task systematically revisits those claims. + +#### Process + +1. List all open issues with the `AI-thinks-windows-only` label, ordered by issue number ascending. +2. Skip issues with number ≤ `woc` (already processed in previous runs). +3. Process up to 5 issues from the remaining list. +4. After processing, set `woc` to the highest issue number you processed. Do NOT reset `woc` to 0 — once all windows-only issues have been revisited, the task naturally has nothing to do until new issues receive the label (which will have higher numbers). + +#### Per-issue assessment + +For each `AI-thinks-windows-only` issue (process up to 5 per run): + +1. **Read the issue carefully.** Understand what the actual bug or feature request is about. + +2. **Classify it honestly.** Ask: "Is the underlying behavior implemented in FSharp.Compiler.Service, or is it purely in VS-specific code (`vsintegration/` WPF/UI layer)?" + + - If the feature is in FCS (classification, tooltips, rename, completions, diagnostics, find references, code fixes, navigation, signature help, etc.) → **it is NOT windows-only**. Remove the `AI-thinks-windows-only` label, then: + 1. Build the compiler and attempt to reproduce the issue on Linux using the repro from the issue (and comments — see "Working with Issues" rules above) + 2. If the issue **still reproduces**: leave a comment with your repro and findings. Do not apply any "fixed" label. + 3. If the issue **no longer reproduces**: apply `AI-thinks-issue-fixed` and add this issue to the Task 2 queue for the current run. Task 2 will then search for existing tests, run adversarial verification, and either point to an existing test or create a regression test PR. + + - If the feature is purely VS chrome (WPF rendering, project system dialogs, VSIX loading, VS-specific key bindings, FSI output pane visual rendering) → the label is correct. Leave it. + +3. **When removing the label**, comment on the issue explaining that the issue's underlying feature (name it: classification, rename, tooltips, etc.) is testable via FSharp.Compiler.Service and is not windows-only. Then proceed to investigate the issue normally. + +#### Goal + +Over successive runs, every `AI-thinks-windows-only` issue will be revisited. Issues that were mislabelled get the label removed and are investigated properly. Issues that are genuinely windows-only keep the label. The end state is a clean, trustworthy set of labels. + ### Task FINAL: Update Monthly Activity Summary Issue (ALWAYS DO THIS TASK IN ADDITION TO OTHERS) Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` as a rolling summary of all Repo Assist activity for the current month. -1. Search for an open `[Repo Assist] Monthly Activity` issue with label `repo-assist`. If it's for the current month, update it. If for a previous month, close it and create a new one. Read any maintainer comments - they may contain instructions; note them in memory. +1. Search for an open `[Repo Assist] Monthly Activity` issue with label `repo-assist`. If it's for the current month, update it. If for a previous month, leave it — a maintainer will close it — and create a new one for the current month. Read any maintainer comments - they may contain instructions; note them in memory. 2. **Issue body format** - use **exactly** this structure: ```markdown @@ -162,8 +336,6 @@ Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` * [ ] **Review PR** #: - [Review]() * [ ] **Check comment** #: Repo Assist commented - verify guidance is helpful - [View]() * [ ] **Merge PR** #: - [Review]() - * [ ] **Close issue** #: - [View]() - * [ ] **Close PR** #: - [View]() * [ ] **Define goal**: - [Related issue]() *(If no actions needed, state "No suggested actions at this time.")* @@ -210,7 +382,7 @@ Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` ## Guidelines - **AI transparency**: every comment, PR, and issue must include a Repo Assist disclosure with 🤖. -- **Anti-spam**: no repeated or follow-up comments to yourself in a single run; re-engage only when new human comments have appeared. +- **Anti-spam**: no redundant or repeated comments to yourself in a single run. Different tasks (investigation vs. test verification) posting on the same issue in the same run is acceptable when each comment serves a distinct purpose. - **Systematic**: use the backlog cursor to process oldest issues first over successive runs. Do not stop early. - **Quality over quantity**: noise erodes trust. Do nothing rather than add low-value output. -- **Bias toward action**: While avoiding spam, actively seek ways to contribute value within the two selected tasks. A "no action" run should be genuinely exceptional. +- **Bias toward action**: While avoiding spam, actively seek ways to contribute value within each task. A "no action" run should be genuinely exceptional. The threshold for commenting is: you have verified evidence (reproduction, test results, or commit references) to support your statement, and that evidence is not apparent from or duplicate with the existing description or comments. From b9e1d9d8f57a5c01deccc0458b9c7f78c29ed157 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:08:01 +0200 Subject: [PATCH 07/19] Update dependencies from https://github.com/dotnet/arcade build 20260327.7 (#19512) On relative base path root Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26168.1 -> To Version 10.0.0-beta.26177.7 Co-authored-by: dotnet-maestro[bot] Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- eng/Version.Details.props | 2 +- eng/Version.Details.xml | 4 ++-- eng/common/core-templates/job/onelocbuild.yml | 4 ++-- .../core-templates/job/publish-build-assets.yml | 4 ++-- .../core-templates/post-build/post-build.yml | 16 ++++++++-------- .../variables/pool-providers.yml | 2 +- .../templates/variables/pool-providers.yml | 2 +- global.json | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 21810fac23e..635450fae4f 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,7 +6,7 @@ This file should be imported by eng/Versions.props - 10.0.0-beta.26168.1 + 10.0.0-beta.26177.7 18.6.0-preview-26173-02 18.6.0-preview-26173-02 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f9870afccc9..46b7f8a211f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -76,9 +76,9 @@ - + https://github.com/dotnet/arcade - 3907f62e877e105b6196b1bd9c309203d6362a0a + 62dc2defffeadabf6761a9ed7e142692107330c0 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml index c5788829a87..eefed3b667a 100644 --- a/eng/common/core-templates/job/onelocbuild.yml +++ b/eng/common/core-templates/job/onelocbuild.yml @@ -52,13 +52,13 @@ jobs: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: AzurePipelines-EO - image: 1ESPT-Windows2022 + image: 1ESPT-Windows2025 demands: Cmd os: windows # If it's not devdiv, it's dnceng ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 + image: windows.vs2026.amd64 os: windows steps: diff --git a/eng/common/core-templates/job/publish-build-assets.yml b/eng/common/core-templates/job/publish-build-assets.yml index b955fac6e13..9afcb8ae159 100644 --- a/eng/common/core-templates/job/publish-build-assets.yml +++ b/eng/common/core-templates/job/publish-build-assets.yml @@ -74,13 +74,13 @@ jobs: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: AzurePipelines-EO - image: 1ESPT-Windows2022 + image: 1ESPT-Windows2025 demands: Cmd os: windows # If it's not devdiv, it's dnceng ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: name: NetCore1ESPool-Publishing-Internal - image: windows.vs2022.amd64 + image: windows.vs2026.amd64 os: windows steps: - ${{ if eq(parameters.is1ESPipeline, '') }}: diff --git a/eng/common/core-templates/post-build/post-build.yml b/eng/common/core-templates/post-build/post-build.yml index b942a79ef02..2df4acb7685 100644 --- a/eng/common/core-templates/post-build/post-build.yml +++ b/eng/common/core-templates/post-build/post-build.yml @@ -120,7 +120,7 @@ stages: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: AzurePipelines-EO - image: 1ESPT-Windows2022 + image: 1ESPT-Windows2025 demands: Cmd os: windows # If it's not devdiv, it's dnceng @@ -164,14 +164,14 @@ stages: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: AzurePipelines-EO - image: 1ESPT-Windows2022 + image: 1ESPT-Windows2025 demands: Cmd os: windows # If it's not devdiv, it's dnceng ${{ else }}: ${{ if eq(parameters.is1ESPipeline, true) }}: name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 + image: windows.vs2026.amd64 os: windows ${{ else }}: name: $(DncEngInternalBuildPool) @@ -225,14 +225,14 @@ stages: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: AzurePipelines-EO - image: 1ESPT-Windows2022 + image: 1ESPT-Windows2025 demands: Cmd os: windows # If it's not devdiv, it's dnceng ${{ else }}: ${{ if eq(parameters.is1ESPipeline, true) }}: name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 + image: windows.vs2026.amd64 os: windows ${{ else }}: name: $(DncEngInternalBuildPool) @@ -286,18 +286,18 @@ stages: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: AzurePipelines-EO - image: 1ESPT-Windows2022 + image: 1ESPT-Windows2025 demands: Cmd os: windows # If it's not devdiv, it's dnceng ${{ else }}: ${{ if eq(parameters.is1ESPipeline, true) }}: name: NetCore1ESPool-Publishing-Internal - image: windows.vs2022.amd64 + image: windows.vs2026.amd64 os: windows ${{ else }}: name: NetCore1ESPool-Publishing-Internal - demands: ImageOverride -equals windows.vs2022.amd64 + demands: ImageOverride -equals windows.vs2026.amd64 steps: - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml parameters: diff --git a/eng/common/templates-official/variables/pool-providers.yml b/eng/common/templates-official/variables/pool-providers.yml index 1f308b24efc..2cc3ae305d5 100644 --- a/eng/common/templates-official/variables/pool-providers.yml +++ b/eng/common/templates-official/variables/pool-providers.yml @@ -23,7 +23,7 @@ # # pool: # name: $(DncEngInternalBuildPool) -# image: 1es-windows-2022 +# image: windows.vs2026.amd64 variables: # Coalesce the target and source branches so we know when a PR targets a release branch diff --git a/eng/common/templates/variables/pool-providers.yml b/eng/common/templates/variables/pool-providers.yml index 18693ea120d..587770f0add 100644 --- a/eng/common/templates/variables/pool-providers.yml +++ b/eng/common/templates/variables/pool-providers.yml @@ -23,7 +23,7 @@ # # pool: # name: $(DncEngInternalBuildPool) -# demands: ImageOverride -equals windows.vs2022.amd64 +# demands: ImageOverride -equals windows.vs2026.amd64 variables: - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - template: /eng/common/templates-official/variables/pool-providers.yml diff --git a/global.json b/global.json index 1b2af8d425c..c222e67a02f 100644 --- a/global.json +++ b/global.json @@ -22,7 +22,7 @@ "xcopy-msbuild": "18.0.0" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.26168.1", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.26177.7", "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2" } } From ab3518b495c89d2e9cbe6afbae722c163aa37204 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:08:52 +0200 Subject: [PATCH 08/19] [main] Update dependencies from dotnet/msbuild (#19493) * Update dependencies from https://github.com/dotnet/msbuild build 20260324.4 On relative base path root Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.6.0-preview-26173-02 -> To Version 18.6.0-preview-26174-04 * Update dependencies from https://github.com/dotnet/msbuild build 20260325.1 On relative base path root Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.6.0-preview-26173-02 -> To Version 18.6.0-preview-26175-01 * Update dependencies from https://github.com/dotnet/msbuild build 20260326.1 On relative base path root Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.6.0-preview-26173-02 -> To Version 18.6.0-preview-26176-01 * Update dependencies from https://github.com/dotnet/msbuild build 20260327.2 On relative base path root Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.6.0-preview-26173-02 -> To Version 18.6.0-preview-26177-02 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- eng/Version.Details.props | 8 ++++---- eng/Version.Details.xml | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 635450fae4f..428b8020e47 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -8,10 +8,10 @@ This file should be imported by eng/Versions.props 10.0.0-beta.26177.7 - 18.6.0-preview-26173-02 - 18.6.0-preview-26173-02 - 18.6.0-preview-26173-02 - 18.6.0-preview-26173-02 + 18.6.0-preview-26177-02 + 18.6.0-preview-26177-02 + 18.6.0-preview-26177-02 + 18.6.0-preview-26177-02 1.0.0-prerelease.26153.1 1.0.0-prerelease.26153.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 46b7f8a211f..f75fe65ed4d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -2,21 +2,21 @@ - + https://github.com/dotnet/msbuild - 6c499a72be37b21dbc32e8b03685aeec3092f599 + db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 - + https://github.com/dotnet/msbuild - 6c499a72be37b21dbc32e8b03685aeec3092f599 + db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 - + https://github.com/dotnet/msbuild - 6c499a72be37b21dbc32e8b03685aeec3092f599 + db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 - + https://github.com/dotnet/msbuild - 6c499a72be37b21dbc32e8b03685aeec3092f599 + db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 https://github.com/dotnet/roslyn From 2e13b48bb0034702e7d6fce91d4422cdf169bcc2 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 30 Mar 2026 19:04:00 +0200 Subject: [PATCH 09/19] Add regression test for #3532: FSharpEntity.IsByRef is false for byref`1 (#19485) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../FSharp.Compiler.Service.Tests/Symbols.fs | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.Service.Tests/Symbols.fs b/tests/FSharp.Compiler.Service.Tests/Symbols.fs index 48235e817c6..f862a46e5e5 100644 --- a/tests/FSharp.Compiler.Service.Tests/Symbols.fs +++ b/tests/FSharp.Compiler.Service.Tests/Symbols.fs @@ -1371,6 +1371,59 @@ let test = System.DateTimeKind.Utc failwith "Expected metadata text, got None" | _ -> failwith "Expected FSharpEntity symbol" +module IsByRef = + // https://github.com/dotnet/fsharp/issues/3532 + [] + let ``FSharpEntity.IsByRef is true for byref return type of address-of operator`` () = + let _, checkResults = + getParseAndCheckResults + """ +let mutable x = 1 +let y = &x +""" + + let symbolUse = findSymbolUseByName "op_AddressOf" checkResults + + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as mfv -> + let retTy = mfv.ReturnParameter.Type + + Assert.True( + retTy.HasTypeDefinition, + $"Expected return type of op_AddressOf to have a TypeDefinition, got: %A{retTy}" + ) + + Assert.True( + retTy.TypeDefinition.IsByRef, + $"Expected return type TypeDefinition.IsByRef = true for op_AddressOf, got entity: %s{retTy.TypeDefinition.DisplayName}" + ) + | symbol -> failwith $"Expected FSharpMemberOrFunctionOrValue but got %A{symbol}" + + [] + let ``FSharpEntity.IsByRef is true for byref type used explicitly`` () = + let _, checkResults = + getParseAndCheckResults + """ +let f (x: byref) = x <- 42 +""" + + let symbolUse = findSymbolUseByName "f" checkResults + + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as mfv -> + let paramTy = mfv.CurriedParameterGroups.[0].[0].Type + + Assert.True( + paramTy.HasTypeDefinition, + $"Expected byref parameter type to have a TypeDefinition, got: %A{paramTy}" + ) + + Assert.True( + paramTy.TypeDefinition.IsByRef, + $"Expected parameter TypeDefinition.IsByRef = true for byref, got entity: %s{paramTy.TypeDefinition.DisplayName}" + ) + | symbol -> failwith $"Expected FSharpMemberOrFunctionOrValue but got %A{symbol}" + module OperatorsWithDots = // https://github.com/dotnet/fsharp/issues/14057 [] @@ -1417,4 +1470,4 @@ let result = 1 -.- 2 let range = usageSymbols.[0].Range let rangeLength = range.EndColumn - range.StartColumn - Assert.Equal(3, rangeLength) \ No newline at end of file + Assert.Equal(3, rangeLength) From 4790e64d3ff01bb4958266ad4ac815826036ce2a Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 30 Mar 2026 21:38:56 +0200 Subject: [PATCH 10/19] Add regression test for #15655: error codes 999 and 3217 are distinct (#19480) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../ErrorMessages/DiagnosticRegressionTests.fs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs index 0f045f297ea..c8517a57e69 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs @@ -3,6 +3,21 @@ module ErrorMessages.DiagnosticRegressionTests open Xunit open FSharp.Test.Compiler +// https://github.com/dotnet/fsharp/issues/15655 +[] +let ``Issue 15655 - error codes 999 and 3217 are distinct`` () = + // Verify that notAFunctionButMaybeIndexerErrorCode (3217) is distinct from packageManagerError (999) + // by triggering a "not a function but maybe indexer" error + FSharp + """ +let d = System.Collections.Generic.Dictionary() +let v = d ["key"] + """ + |> typecheck + |> shouldFail + |> withErrorCode 3217 + + // https://github.com/dotnet/fsharp/issues/13697 [] let ``Issue 13697 - typeof with out of scope type in attribute should report FS0039`` () = @@ -17,7 +32,8 @@ type Vehicle() = class end |> withDiagnostics [ (Error 39, Line 3, Col 14, Line 3, Col 28, "The type 'OutOfScopeType' is not defined.") (Error 267, Line 3, Col 7, Line 3, Col 29, "This is not a valid constant expression or custom attribute value") ] - + + // https://github.com/dotnet/fsharp/issues/16410 [] let ``Issue 16410 - no spurious FS3570 warning with KeyValue active pattern`` () = From 06924ecd10305b4b2d08dc7b9eabda32305ae718 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 30 Mar 2026 21:41:32 +0200 Subject: [PATCH 11/19] Add regression test: #13519, C# optional parameters from F# (#19473) * Add regression test for #13519: C# optional parameters from F# Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add ParamArray + optional params regression test for #13519 Addresses reviewer feedback: the original issue was specifically about the intersection of omitted optional arguments and ParamArray arguments, as identified by Don Syme. This adds a test covering that exact scenario. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../Interop/SimpleInteropTests.fs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs index 6499cbf9259..00a5781553f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs @@ -114,3 +114,112 @@ Holder.Label <- "nope" fsLib |> compile |> shouldFail + + // https://github.com/dotnet/fsharp/issues/13519 + [] + let ``Issue 13519 - C# method with optional parameters can be called from F# without specifying defaults`` () = + let csLib = + CSharp + """ +using System; + +namespace CSharpLib +{ + public class MyClass + { + public string DoSomething(string required, string optional1 = "default1", string optional2 = "default2") + { + return required + "|" + optional1 + "|" + optional2; + } + } +} + """ + |> withName "CSharpOptionalParams" + + let fsApp = + FSharp + """ +module TestApp + +open CSharpLib + +[] +let main _ = + let c = MyClass() + let result = c.DoSomething("hello") + if result <> "hello|default1|default2" then + failwithf "Expected 'hello|default1|default2' but got '%s'" result + let result2 = c.DoSomething("hello", "custom1") + if result2 <> "hello|custom1|default2" then + failwithf "Expected 'hello|custom1|default2' but got '%s'" result2 + 0 + """ + |> withReferences [ csLib ] + + fsApp + |> asExe + |> compileExeAndRun + |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/13519 + // Specifically testing the intersection of optional parameters and ParamArray + // as identified by Don Syme: https://github.com/dotnet/fsharp/issues/13519#issuecomment-1253808416 + [] + let ``Issue 13519 - C# method with optional parameters and ParamArray can be called from F# without specifying defaults`` () = + let csLib = + CSharp + """ +using System; + +namespace CSharpParamArrayLib +{ + public class Assertions + { + public string BeEquivalentTo(string expected, string because = "", params object[] becauseArgs) + { + string formatted = because; + if (becauseArgs != null && becauseArgs.Length > 0) + { + formatted = string.Format(because, becauseArgs); + } + return expected + "|" + formatted + "|" + becauseArgs.Length; + } + } +} + """ + |> withName "CSharpParamArrayLib" + + let fsApp = + FSharp + """ +module TestParamArrayApp + +open CSharpParamArrayLib + +[] +let main _ = + let a = Assertions() + + // Call with only the required argument - omitting both optional and params + let result1 = a.BeEquivalentTo("test") + if result1 <> "test||0" then + failwithf "Test 1 failed: Expected 'test||0' but got '%s'" result1 + + // Call with required + optional, omitting params + let result2 = a.BeEquivalentTo("test", "because {0}") + if result2 <> "test|because {0}|0" then + failwithf "Test 2 failed: Expected 'test|because {0}|0' but got '%s'" result2 + + // Call with all arguments including params values + let result3 = a.BeEquivalentTo("test", "because {0}", "reason") + if result3 <> "test|because reason|1" then + failwithf "Test 3 failed: Expected 'test|because reason|1' but got '%s'" result3 + + 0 + """ + |> withReferences [ csLib ] + + fsApp + |> asExe + |> compileExeAndRun + |> shouldSucceed From 69c535f9c437ec5bf7a93a719e78218939c30927 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 31 Mar 2026 02:58:21 +0200 Subject: [PATCH 12/19] Add regression test: #6648, DU of DUs with inline static members (#19470) * Add regression test for #6648: DU of DUs with inline static members Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix unclosed triple-quoted string in Issue 6648 regression test Add missing closing triple-quote and assertion pipeline to the DU of DUs with inline static members test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../ConstraintSolver/MemberConstraints.fs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs index 905d0594e26..5f424466c2f 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -114,6 +114,42 @@ ignore ["1" .. "42"] |> withSingleDiagnostic (Error 1, Line 2, Col 9, Line 2, Col 12, "The type 'string' does not support the operator 'op_Range'") + // https://github.com/dotnet/fsharp/issues/6648 + [] + let ``Issue 6648 - DU of DUs with inline static members should compile`` () = + FSharp + """ +type SomeUnion1<'T> = + | Case1A of 'T + | Case1B of 'T + static member inline (-) (a, b) = + match a, b with + | Case1A x, Case1A y -> Case1A(x - y) + | Case1B x, Case1B y -> Case1B(x - y) + | _ -> failwith "mismatch" + +type SomeUnion2<'T> = + | Case2A of 'T + | Case2B of 'T + static member inline (-) (a, b) = + match a, b with + | Case2A x, Case2A y -> Case2A(x - y) + | Case2B x, Case2B y -> Case2B(x - y) + | _ -> failwith "mismatch" + +type UnionOfUnions<'T> = + | ParentCase1 of SomeUnion1<'T> + | ParentCase2 of SomeUnion2<'T> + static member inline (-) (a, b) = + match a, b with + | ParentCase1 x, ParentCase1 y -> x - y |> ParentCase1 + | ParentCase2 x, ParentCase2 y -> x - y |> ParentCase2 + | _ -> failwith "mismatch" + """ + |> asLibrary + |> typecheck + |> shouldSucceed + // https://github.com/dotnet/fsharp/issues/9382 [] let ``Issue 9382 - SRTP stress test with matrix inverse should compile`` () = From 24bf1860f80ba41548d2d0cb2790c524ff538fac Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:23:48 +0200 Subject: [PATCH 13/19] Fix repo-assist: add safe output discipline and iteration limits (#19516) * Initial plan * Fix repo-assist: add safe output discipline, iteration limits, and noop fallback Root cause: Agent spent ~37 minutes creating ~25 test files across 5+ issues without calling any safe output MCP tools, resulting in empty agent_output.json. - Add "Safe Output Discipline" section with incremental output, noop fallback, 3-attempt iteration limit per issue, and time awareness rules - Task 1: call safe output tools immediately after each issue - Task 2: limit build-and-test cycles to 3 per issue, create PRs immediately, do not create multiple test file variants Agent-Logs-Url: https://github.com/dotnet/fsharp/sessions/cf589816-f234-44e2-9245-742907ee5d27 Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> * Run gh aw upgrade and gh aw compile to regenerate lock files Updates gh-aw from v0.64.2 to v0.64.4: - Regenerate repo-assist.lock.yml with new frontmatter hash - Regenerate regression-pr-shepherd.lock.yml - Update actions-lock.json with new action SHAs - Update agentic-workflows.agent.md version references Agent-Logs-Url: https://github.com/dotnet/fsharp/sessions/0f6b9ce7-da31-403c-b633-6bb5f004484e Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> Co-authored-by: Tomas Grosup Co-authored-by: Adam Boniecki <20281641+abonie@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .github/agents/agentic-workflows.agent.md | 22 ++--- .github/aw/actions-lock.json | 12 +-- .../workflows/regression-pr-shepherd.lock.yml | 58 +++++------ .github/workflows/repo-assist.lock.yml | 98 +++++++++---------- .github/workflows/repo-assist.md | 20 +++- 5 files changed, 111 insertions(+), 99 deletions(-) diff --git a/.github/agents/agentic-workflows.agent.md b/.github/agents/agentic-workflows.agent.md index 7ed300e00cc..b87715723a8 100644 --- a/.github/agents/agentic-workflows.agent.md +++ b/.github/agents/agentic-workflows.agent.md @@ -30,7 +30,7 @@ Workflows may optionally include: - Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` - Workflow lock files: `.github/workflows/*.lock.yml` - Shared components: `.github/workflows/shared/*.md` -- Configuration: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/github-agentic-workflows.md +- Configuration: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/github-agentic-workflows.md ## Problems This Solves @@ -52,7 +52,7 @@ When you interact with this agent, it will: ### Create New Workflow **Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/create-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/create-agentic-workflow.md **Use cases**: - "Create a workflow that triages issues" @@ -62,7 +62,7 @@ When you interact with this agent, it will: ### Update Existing Workflow **Load when**: User wants to modify, improve, or refactor an existing workflow -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/update-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/update-agentic-workflow.md **Use cases**: - "Add web-fetch tool to the issue-classifier workflow" @@ -72,7 +72,7 @@ When you interact with this agent, it will: ### Debug Workflow **Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/debug-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/debug-agentic-workflow.md **Use cases**: - "Why is this workflow failing?" @@ -82,7 +82,7 @@ When you interact with this agent, it will: ### Upgrade Agentic Workflows **Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/upgrade-agentic-workflows.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/upgrade-agentic-workflows.md **Use cases**: - "Upgrade all workflows to the latest version" @@ -92,7 +92,7 @@ When you interact with this agent, it will: ### Create a Report-Generating Workflow **Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/report.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/report.md **Use cases**: - "Create a weekly CI health report" @@ -102,7 +102,7 @@ When you interact with this agent, it will: ### Create Shared Agentic Workflow **Load when**: User wants to create a reusable workflow component or wrap an MCP server -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/create-shared-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/create-shared-agentic-workflow.md **Use cases**: - "Create a shared component for Notion integration" @@ -112,7 +112,7 @@ When you interact with this agent, it will: ### Fix Dependabot PRs **Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/dependabot.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/dependabot.md **Use cases**: - "Fix the open Dependabot PRs for npm dependencies" @@ -122,7 +122,7 @@ When you interact with this agent, it will: ### Analyze Test Coverage **Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. -**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/test-coverage.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/test-coverage.md **Use cases**: - "Create a workflow that comments coverage on PRs" @@ -169,10 +169,10 @@ gh aw compile --validate ## Important Notes -- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/github-agentic-workflows.md for complete documentation +- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/github-agentic-workflows.md for complete documentation - Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud - Workflows must be compiled to `.lock.yml` files before running in GitHub Actions - **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF - Follow security best practices: minimal permissions, explicit network access, no template injection -- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.64.4/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. - **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index a3de9b4b5d1..004e5d492ba 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -5,15 +5,15 @@ "version": "v8", "sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd" }, - "github/gh-aw-actions/setup@v0.64.2": { + "github/gh-aw-actions/setup@v0.64.4": { "repo": "github/gh-aw-actions/setup", - "version": "v0.64.2", - "sha": "f22886a9607f5c27e79742a8bfc5faa34737138b" + "version": "v0.64.4", + "sha": "7cae8cd356c7905aeda72eb08e1d0b4501310c23" }, - "github/gh-aw/actions/setup@v0.64.2": { + "github/gh-aw/actions/setup@v0.64.4": { "repo": "github/gh-aw/actions/setup", - "version": "v0.64.2", - "sha": "72346ee09bdaa904d167f1be907e590fd9128fa3" + "version": "v0.64.4", + "sha": "0b76aaa0e858759e04c1d89599a1041025a24d69" } } } diff --git a/.github/workflows/regression-pr-shepherd.lock.yml b/.github/workflows/regression-pr-shepherd.lock.yml index 92b9aba5bf5..1466fac83c6 100644 --- a/.github/workflows/regression-pr-shepherd.lock.yml +++ b/.github/workflows/regression-pr-shepherd.lock.yml @@ -12,7 +12,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.64.2). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.64.4). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -25,7 +25,7 @@ # actually proves the bug still exists. # Runs 6 times per day. # -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"83657c4bc08a81d82e8fbf14c41ebe0e941dcd4c5984fe0b5501193e58921dd6","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"83657c4bc08a81d82e8fbf14c41ebe0e941dcd4c5984fe0b5501193e58921dd6","compiler_version":"v0.64.4","strict":true,"agent_id":"copilot"} name: "Regression PR Shepherd" "on": @@ -60,7 +60,7 @@ jobs: secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Generate agentic run info @@ -71,14 +71,14 @@ jobs: GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} GH_AW_INFO_VERSION: "latest" GH_AW_INFO_AGENT_VERSION: "latest" - GH_AW_INFO_CLI_VERSION: "v0.64.2" + GH_AW_INFO_CLI_VERSION: "v0.64.4" GH_AW_INFO_WORKFLOW_NAME: "Regression PR Shepherd" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.1" + GH_AW_INFO_AWF_VERSION: "v0.25.4" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -279,7 +279,7 @@ jobs: output_types: ${{ steps.collect_output.outputs.output_types }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Set runtime paths @@ -336,10 +336,8 @@ jobs: await main(); - name: Install GitHub Copilot CLI run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest - env: - GH_HOST: github.com - name: Install AWF binary - run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.4 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -347,7 +345,7 @@ jobs: GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} run: bash ${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh - name: Download container images - run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.4 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.4 ghcr.io/github/gh-aw-firewall/squid:0.25.4 ghcr.io/github/gh-aw-mcpg:v0.2.9 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs @@ -549,7 +547,7 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.9' mkdir -p /home/runner/.copilot cat << GH_AW_MCP_CONFIG_a0f4ea742639b7d6_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh @@ -612,7 +610,7 @@ jobs: set -o pipefail touch /tmp/gh-aw/agent-step-summary.md # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains '*.vsblob.vsassets.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.vsblob.vsassets.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.4 --skip-pull --enable-api-proxy \ -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -622,7 +620,7 @@ jobs: GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.64.2 + GH_AW_VERSION: v0.64.4 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -780,13 +778,12 @@ jobs: /tmp/gh-aw/sandbox/agent/logs/ /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/proxy-logs/ - !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ /tmp/gh-aw/safeoutputs.jsonl /tmp/gh-aw/agent_output.json /tmp/gh-aw/aw-*.patch + /tmp/gh-aw/aw-*.bundle if-no-files-found: ignore - name: Upload firewall audit logs if: always() @@ -822,7 +819,7 @@ jobs: total_count: ${{ steps.missing_tool.outputs.total_count }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -858,6 +855,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "Regression PR Shepherd" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -916,14 +914,15 @@ jobs: detection: needs: agent - if: always() && needs.agent.result != 'skipped' + if: > + always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true') runs-on: ubuntu-latest outputs: detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} detection_success: ${{ steps.detection_conclusion.outputs.success }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -942,7 +941,7 @@ jobs: echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" # --- Threat Detection --- - name: Download container images - run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.4 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.4 ghcr.io/github/gh-aw-firewall/squid:0.25.4 - name: Check if detection needed id: detection_guard if: always() @@ -972,6 +971,9 @@ jobs: for f in /tmp/gh-aw/aw-*.patch; do [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true done + for f in /tmp/gh-aw/aw-*.bundle; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done echo "Prepared threat detection files:" ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true - name: Setup threat detection @@ -994,10 +996,8 @@ jobs: touch /tmp/gh-aw/threat-detection/detection.log - name: Install GitHub Copilot CLI run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest - env: - GH_HOST: github.com - name: Install AWF binary - run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.4 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' id: detection_agentic_execution @@ -1007,7 +1007,7 @@ jobs: set -o pipefail touch /tmp/gh-aw/agent-step-summary.md # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.4 --skip-pull --enable-api-proxy \ -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -1015,7 +1015,7 @@ jobs: COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.64.2 + GH_AW_VERSION: v0.64.4 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -1052,12 +1052,12 @@ jobs: needs: - agent - detection - if: always() && needs.detection.result == 'success' - runs-on: ubuntu-latest + if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped') + runs-on: ubuntu-slim permissions: contents: write concurrency: - group: "push-repo-memory-${{ github.repository }}" + group: "push-repo-memory-${{ github.repository }}|memory/regression-pr-shepherd" cancel-in-progress: false outputs: patch_size_exceeded_default: ${{ steps.push_repo_memory_default.outputs.patch_size_exceeded }} @@ -1065,7 +1065,7 @@ jobs: validation_failed_default: ${{ steps.push_repo_memory_default.outputs.validation_failed }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Checkout repository @@ -1146,7 +1146,7 @@ jobs: push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact diff --git a/.github/workflows/repo-assist.lock.yml b/.github/workflows/repo-assist.lock.yml index 06789634de0..9086ea42257 100644 --- a/.github/workflows/repo-assist.lock.yml +++ b/.github/workflows/repo-assist.lock.yml @@ -12,7 +12,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.64.2). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.64.4). DO NOT EDIT. # # To update this file, edit githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02 and run: # gh aw compile @@ -35,7 +35,7 @@ # # Source: githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02 # -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"1bb4c53e8ede8f6c3a7e9d9a0fdc6f804d5abda2a2657c0831e4a4c9689822e4","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"b09f3395fc1a506af9e7289541ecf17a0b192c57e9dd7c2d578d1ce750da838f","compiler_version":"v0.64.4","strict":true,"agent_id":"copilot"} name: "Repo Assist" "on": @@ -105,7 +105,7 @@ jobs: title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Generate agentic run info @@ -116,14 +116,14 @@ jobs: GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} GH_AW_INFO_VERSION: "latest" GH_AW_INFO_AGENT_VERSION: "latest" - GH_AW_INFO_CLI_VERSION: "v0.64.2" + GH_AW_INFO_CLI_VERSION: "v0.64.4" GH_AW_INFO_WORKFLOW_NAME: "Repo Assist" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","python"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.1" + GH_AW_INFO_AWF_VERSION: "v0.25.4" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -212,21 +212,21 @@ jobs: run: | bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh { - cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' + cat << 'GH_AW_PROMPT_737e7e7a7b6612d8_EOF' - GH_AW_PROMPT_5cd45711b7cf54eb_EOF + GH_AW_PROMPT_737e7e7a7b6612d8_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/repo_memory_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' + cat << 'GH_AW_PROMPT_737e7e7a7b6612d8_EOF' Tools: add_comment(max:10), create_issue(max:4), update_issue, create_pull_request(max:10), add_labels(max:30), remove_labels(max:10), push_to_pull_request_branch(max:10), missing_tool, missing_data, noop - GH_AW_PROMPT_EOF + GH_AW_PROMPT_737e7e7a7b6612d8_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_EOF' + cat << 'GH_AW_PROMPT_737e7e7a7b6612d8_EOF' The following GitHub context information is available for this workflow: @@ -256,17 +256,17 @@ jobs: {{/if}} - GH_AW_PROMPT_5cd45711b7cf54eb_EOF + GH_AW_PROMPT_737e7e7a7b6612d8_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md" fi - cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' + cat << 'GH_AW_PROMPT_737e7e7a7b6612d8_EOF' - GH_AW_PROMPT_5cd45711b7cf54eb_EOF - cat << 'GH_AW_PROMPT_5cd45711b7cf54eb_EOF' + GH_AW_PROMPT_737e7e7a7b6612d8_EOF + cat << 'GH_AW_PROMPT_737e7e7a7b6612d8_EOF' {{#runtime-import .github/workflows/repo-assist.md}} - GH_AW_PROMPT_5cd45711b7cf54eb_EOF + GH_AW_PROMPT_737e7e7a7b6612d8_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -377,7 +377,7 @@ jobs: output_types: ${{ steps.collect_output.outputs.output_types }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Set runtime paths @@ -434,10 +434,8 @@ jobs: await main(); - name: Install GitHub Copilot CLI run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest - env: - GH_HOST: github.com - name: Install AWF binary - run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.4 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -445,18 +443,18 @@ jobs: GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} run: bash ${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh - name: Download container images - run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.4 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.4 ghcr.io/github/gh-aw-firewall/squid:0.25.4 ghcr.io/github/gh-aw-mcpg:v0.2.9 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_1b5f35ab740ec175_EOF' - {"add_comment":{"hide_older_comments":true,"max":10,"target":"*"},"add_labels":{"allowed":["AI-thinks-issue-fixed","AI-thinks-windows-only"],"max":30,"target":"*"},"create_issue":{"labels":["automation","repo-assist"],"max":4,"title_prefix":"[Repo Assist] "},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":10240,"max_patch_size":10240}]},"update_issue":{"allow_body":true,"max":1,"target":"*","title_prefix":"[Repo Assist] "}} - GH_AW_SAFE_OUTPUTS_CONFIG_1b5f35ab740ec175_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_6b66c6d773bf40cb_EOF' + {"add_comment":{"hide_older_comments":true,"max":10,"target":"*"},"add_labels":{"allowed":["AI-thinks-issue-fixed","AI-thinks-windows-only"],"max":30,"target":"*"},"create_issue":{"labels":["automation","repo-assist"],"max":4,"title_prefix":"[Repo Assist] "},"create_pull_request":{"allowed_files":["tests/**","vsintegration/tests/**"],"auto_merge":true,"draft":false,"labels":["NO_RELEASE_NOTES","AI-Issue-Regression-PR"],"max":10,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_path_prefixes":[".github/",".agents/"],"reviewers":["abonie","T-Gro"],"title_prefix":"Add regression test: "},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":10240,"max_patch_size":10240}]},"push_to_pull_request_branch":{"if_no_changes":"warn","labels":["AI-Issue-Regression-PR"],"max":10,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_path_prefixes":[".github/",".agents/"],"target":"*","title_prefix":"Add regression test: "},"remove_labels":{"allowed":["AI-thinks-issue-fixed","AI-thinks-windows-only"],"max":10,"target":"*"},"update_issue":{"allow_body":true,"max":1,"target":"*","title_prefix":"[Repo Assist] "}} + GH_AW_SAFE_OUTPUTS_CONFIG_6b66c6d773bf40cb_EOF - name: Write Safe Outputs Tools run: | - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_a46ff0c1b20be7a8_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_cd4ef13107bcace0_EOF' { "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *.", @@ -470,8 +468,8 @@ jobs: "repo_params": {}, "dynamic_tools": [] } - GH_AW_SAFE_OUTPUTS_TOOLS_META_a46ff0c1b20be7a8_EOF - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_db806f7f6689b41b_EOF' + GH_AW_SAFE_OUTPUTS_TOOLS_META_cd4ef13107bcace0_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_540edf6717e0806e_EOF' { "add_comment": { "defaultMax": 1, @@ -730,7 +728,7 @@ jobs: "customValidation": "requiresOneOf:status,title,body" } } - GH_AW_SAFE_OUTPUTS_VALIDATION_db806f7f6689b41b_EOF + GH_AW_SAFE_OUTPUTS_VALIDATION_540edf6717e0806e_EOF node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs - name: Generate Safe Outputs MCP Server Config id: safe-outputs-config @@ -793,10 +791,10 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.9' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_63fbaf7b58f9c92e_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + cat << GH_AW_MCP_CONFIG_3e5431fa1b9e9da2_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh { "mcpServers": { "github": { @@ -839,7 +837,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_63fbaf7b58f9c92e_EOF + GH_AW_MCP_CONFIG_3e5431fa1b9e9da2_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -856,7 +854,7 @@ jobs: set -o pipefail touch /tmp/gh-aw/agent-step-summary.md # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains '*.pythonhosted.org,*.vsblob.vsassets.io,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.pythonhosted.org,*.vsblob.vsassets.io,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.4 --skip-pull --enable-api-proxy \ -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -866,7 +864,7 @@ jobs: GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.64.2 + GH_AW_VERSION: v0.64.4 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -1025,13 +1023,12 @@ jobs: /tmp/gh-aw/sandbox/agent/logs/ /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/proxy-logs/ - !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ /tmp/gh-aw/safeoutputs.jsonl /tmp/gh-aw/agent_output.json /tmp/gh-aw/aw-*.patch + /tmp/gh-aw/aw-*.bundle if-no-files-found: ignore - name: Upload firewall audit logs if: always() @@ -1067,7 +1064,7 @@ jobs: total_count: ${{ steps.missing_tool.outputs.total_count }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -1105,6 +1102,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "Repo Assist" GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02" GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9135cdfde26838a01779aa966628308404ec1f02/workflows/repo-assist.md" @@ -1203,14 +1201,15 @@ jobs: detection: needs: agent - if: always() && needs.agent.result != 'skipped' + if: > + always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true') runs-on: ubuntu-latest outputs: detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} detection_success: ${{ steps.detection_conclusion.outputs.success }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact @@ -1229,7 +1228,7 @@ jobs: echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" # --- Threat Detection --- - name: Download container images - run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.4 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.4 ghcr.io/github/gh-aw-firewall/squid:0.25.4 - name: Check if detection needed id: detection_guard if: always() @@ -1259,6 +1258,9 @@ jobs: for f in /tmp/gh-aw/aw-*.patch; do [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true done + for f in /tmp/gh-aw/aw-*.bundle; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done echo "Prepared threat detection files:" ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true - name: Setup threat detection @@ -1281,10 +1283,8 @@ jobs: touch /tmp/gh-aw/threat-detection/detection.log - name: Install GitHub Copilot CLI run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest - env: - GH_HOST: github.com - name: Install AWF binary - run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.4 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' id: detection_agentic_execution @@ -1294,7 +1294,7 @@ jobs: set -o pipefail touch /tmp/gh-aw/agent-step-summary.md # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.4 --skip-pull --enable-api-proxy \ -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -1302,7 +1302,7 @@ jobs: COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.64.2 + GH_AW_VERSION: v0.64.4 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -1343,7 +1343,7 @@ jobs: matched_command: ${{ steps.check_command_position.outputs.matched_command }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Check team membership for command workflow @@ -1374,12 +1374,12 @@ jobs: needs: - agent - detection - if: always() && needs.detection.result == 'success' - runs-on: ubuntu-latest + if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped') + runs-on: ubuntu-slim permissions: contents: write concurrency: - group: "push-repo-memory-${{ github.repository }}" + group: "push-repo-memory-${{ github.repository }}|memory/repo-assist" cancel-in-progress: false outputs: patch_size_exceeded_default: ${{ steps.push_repo_memory_default.outputs.patch_size_exceeded }} @@ -1387,7 +1387,7 @@ jobs: validation_failed_default: ${{ steps.push_repo_memory_default.outputs.validation_failed }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Checkout repository @@ -1474,7 +1474,7 @@ jobs: push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 with: destination: ${{ runner.temp }}/gh-aw/actions - name: Download agent output artifact diff --git a/.github/workflows/repo-assist.md b/.github/workflows/repo-assist.md index 731b9a73b72..42983a61ec8 100644 --- a/.github/workflows/repo-assist.md +++ b/.github/workflows/repo-assist.md @@ -178,7 +178,7 @@ Each run, do Task 1, Task 3, Task 2, and Task FINAL (in this order — Task 3 fe If you previously labelled issues as windows-only that fall into the testable category above, you were wrong. Task 3 below will systematically revisit and correct those. - Otherwise, do nothing to avoid noise. If you don't have high confidence in a fix, it's better to say nothing than to risk a false positive. If you have some other high-confidence judgement, leave a note in the "Additional observations" section of the Monthly Activity Summary. If you have written a solid reproduction not yet covered in the issue, write it down — this helps future implementers. -4. Expect to engage substantively on 1–10 issues per run; you may scan many more to find good candidates. +4. Expect to engage substantively on 1–10 issues per run; you may scan many more to find good candidates. **After each issue where you comment or label, call the safe output tool immediately** — do not defer outputs. 5. Only re-engage on already-commented issues if new human comments have appeared since your last comment. 6. Begin every comment with: `🤖 *This is an automated response from Repo Assist.*` 7. Update memory with comments made and the new cursor position - and also the second cursor for "windows-only" reassessment. @@ -245,13 +245,13 @@ This is the primary expected outcome when no existing test is found. |> shouldSucceed ``` -3. **Build and run the test** to confirm it passes: +3. **Build and run the test** to confirm it passes. **Limit yourself to at most 3 build-and-test cycles per issue** — if the test still doesn't pass after 3 attempts, the issue is likely not fixed (go to step 5). Do not create multiple test file variants; iterate on a single test file: ```bash dotnet build tests/{TestProject}/{TestProject}.fsproj -c Release dotnet test tests/{TestProject}/{TestProject}.fsproj -c Release --no-build -- --filter-method "*Issue {number}*" ``` -4. **If the test PASSES**: Before creating a PR, run the duplicate check from Step A one more time (another run may have created a PR since you last checked). Then create the PR: +4. **If the test PASSES**: Before creating a PR, run the duplicate check from Step A one more time (another run may have created a PR since you last checked). Then create the PR **immediately** (do not defer to the end of the run): - Branch: `regression-test/issue{number}` - Title: `Add regression test: #{number}, {brief description}` - Body: **Must** contain `Fixes https://github.com/dotnet/fsharp/issues/{number}` on its own line — this is non-negotiable. GitHub automatically closes the issue when the PR is merged. This is the ONLY mechanism for closing issues. The workflow must never close issues directly. @@ -260,7 +260,7 @@ This is the primary expected outcome when no existing test is found. - Auto-merge: squash - If the .fsproj needs a new `` entry, add it in alphabetical order within its section -5. **If the test FAILS**: The issue is **not fixed**. Do all of the following: +5. **If the test FAILS** (including after exhausting the 3-attempt limit): The issue is **not fixed**. Do all of the following **immediately** (do not defer): - **Remove** the `AI-thinks-issue-fixed` label from the issue - **Comment** on the issue with the test code, the failure output, and the conclusion that the issue remains open - Do **not** create a PR @@ -386,3 +386,15 @@ Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` - **Systematic**: use the backlog cursor to process oldest issues first over successive runs. Do not stop early. - **Quality over quantity**: noise erodes trust. Do nothing rather than add low-value output. - **Bias toward action**: While avoiding spam, actively seek ways to contribute value within each task. A "no action" run should be genuinely exceptional. The threshold for commenting is: you have verified evidence (reproduction, test results, or commit references) to support your statement, and that evidence is not apparent from or duplicate with the existing description or comments. + +## Safe Output Discipline + +Every run **must** produce at least one safe output call. Follow these rules: + +1. **Produce outputs incrementally.** After completing work on each issue (commenting, labeling, creating a PR), call the safe output tool **immediately** — do not batch all outputs until the end of the run. This ensures partial work is captured even if the run is interrupted or you exhaust your context window. + +2. **Call `noop` if no action is warranted.** If after completing all tasks you have genuinely nothing to output (no comments, no labels, no PRs, no monthly summary update), call the `noop` tool with a brief explanation (e.g., "All scanned issues already have Repo Assist comments and no new activity since last run"). A run that produces zero safe outputs is treated as a failure by the workflow infrastructure. + +3. **Limit iteration on any single issue.** When writing a regression test (Task 2), allow at most **3 build-and-test cycles** per issue. If the test still fails after 3 attempts, conclude that the issue is not fixed: remove the `AI-thinks-issue-fixed` label, comment with your findings and the failing test code, and move on. Do not spend unbounded time iterating on a single test. + +4. **Time awareness.** You have a 60-minute timeout. Reserve at least 10 minutes for Task FINAL (monthly summary update). If you are deep in Task 2 test creation and have used over 40 minutes, wrap up the current issue and proceed to Task FINAL. From fd6b6846c391c5218c5ad390c5f74ae8a56e68ac Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:25:27 +0200 Subject: [PATCH 14/19] Update dependencies from https://github.com/dotnet/msbuild build 20260330.8 (#19525) On relative base path root Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.6.0-preview-26177-02 -> To Version 18.6.0-preview-26180-08 Co-authored-by: dotnet-maestro[bot] Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- eng/Version.Details.props | 8 ++++---- eng/Version.Details.xml | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 428b8020e47..fad9e32a7a0 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -8,10 +8,10 @@ This file should be imported by eng/Versions.props 10.0.0-beta.26177.7 - 18.6.0-preview-26177-02 - 18.6.0-preview-26177-02 - 18.6.0-preview-26177-02 - 18.6.0-preview-26177-02 + 18.6.0-preview-26180-08 + 18.6.0-preview-26180-08 + 18.6.0-preview-26180-08 + 18.6.0-preview-26180-08 1.0.0-prerelease.26153.1 1.0.0-prerelease.26153.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f75fe65ed4d..2a22ad5327a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -2,21 +2,21 @@ - + https://github.com/dotnet/msbuild - db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 + 8a330c4406f03bafa3006d1e1213ec5c62252640 - + https://github.com/dotnet/msbuild - db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 + 8a330c4406f03bafa3006d1e1213ec5c62252640 - + https://github.com/dotnet/msbuild - db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 + 8a330c4406f03bafa3006d1e1213ec5c62252640 - + https://github.com/dotnet/msbuild - db5eca3d0f2c02edc7caf5ceb64ee01547e360b5 + 8a330c4406f03bafa3006d1e1213ec5c62252640 https://github.com/dotnet/roslyn From b0c25110efa263e4cacbf5eec5ae4e8efdc033fb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:25:35 +0200 Subject: [PATCH 15/19] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20260330.1 (#19523) On relative base path root optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime From Version 1.0.0-prerelease.26153.1 -> To Version 1.0.0-prerelease.26180.1 Co-authored-by: dotnet-maestro[bot] Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- eng/Version.Details.props | 10 +++++----- eng/Version.Details.xml | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/eng/Version.Details.props b/eng/Version.Details.props index fad9e32a7a0..15b90be4221 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -13,11 +13,11 @@ This file should be imported by eng/Versions.props 18.6.0-preview-26180-08 18.6.0-preview-26180-08 - 1.0.0-prerelease.26153.1 - 1.0.0-prerelease.26153.1 - 1.0.0-prerelease.26153.1 - 1.0.0-prerelease.26153.1 - 1.0.0-prerelease.26153.1 + 1.0.0-prerelease.26180.1 + 1.0.0-prerelease.26180.1 + 1.0.0-prerelease.26180.1 + 1.0.0-prerelease.26180.1 + 1.0.0-prerelease.26180.1 5.6.0-2.26173.11 5.6.0-2.26173.11 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2a22ad5327a..691a605fa66 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -80,25 +80,25 @@ https://github.com/dotnet/arcade 62dc2defffeadabf6761a9ed7e142692107330c0 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - b194351e54adc9538bb2a0b6a188f8f897fa223c + 9f55ee44f6d99b78f3e80f77e2ed73fb73b8f63b - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - b194351e54adc9538bb2a0b6a188f8f897fa223c + 9f55ee44f6d99b78f3e80f77e2ed73fb73b8f63b - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - b194351e54adc9538bb2a0b6a188f8f897fa223c + 9f55ee44f6d99b78f3e80f77e2ed73fb73b8f63b - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - b194351e54adc9538bb2a0b6a188f8f897fa223c + 9f55ee44f6d99b78f3e80f77e2ed73fb73b8f63b - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - b194351e54adc9538bb2a0b6a188f8f897fa223c + 9f55ee44f6d99b78f3e80f77e2ed73fb73b8f63b From 10b4e176431d6a17d1b915baf9c148c85edb7196 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 31 Mar 2026 11:39:35 +0200 Subject: [PATCH 16/19] Add aw-auto-update workflow + upgrade to v0.64.4 (#19519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add aw-auto-update workflow for daily gh aw upgrade/compile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update agentic workflows via gh aw upgrade (v0.64.2 → v0.64.4) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .github/workflows/aw-auto-update.lock.yml | 1136 +++++++++++++++++++++ .github/workflows/aw-auto-update.md | 61 ++ 2 files changed, 1197 insertions(+) create mode 100644 .github/workflows/aw-auto-update.lock.yml create mode 100644 .github/workflows/aw-auto-update.md diff --git a/.github/workflows/aw-auto-update.lock.yml b/.github/workflows/aw-auto-update.lock.yml new file mode 100644 index 00000000000..02181b3b1ca --- /dev/null +++ b/.github/workflows/aw-auto-update.lock.yml @@ -0,0 +1,1136 @@ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ +# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ +# +# This file was automatically generated by gh-aw (v0.64.4). DO NOT EDIT. +# +# To update this file, edit the corresponding .md file and run: +# gh aw compile +# Not all edits will cause changes to this file. +# +# For more information: https://github.github.com/gh-aw/introduction/overview/ +# +# Keeps agentic workflows up to date by running `gh aw upgrade` and `gh aw compile` daily. +# If changes are detected, pushes them to a long-lived branch and creates or updates a PR. +# +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"cee3cbbc17a8d1be9fcf671400323b7e1b15d416cb0ec65fbdb6f441e0e9a1a9","compiler_version":"v0.64.4","strict":true,"agent_id":"copilot"} + +name: "Agentic Workflow Auto-Update" +"on": + schedule: + - cron: "52 */24 * * *" + # Friendly format: every 24h (scattered) + workflow_dispatch: + inputs: + aw_context: + default: "" + description: Agent caller context (used internally by Agentic Workflows). + required: false + type: string + +permissions: {} + +concurrency: + group: "gh-aw-${{ github.workflow }}" + +run-name: "Agentic Workflow Auto-Update" + +jobs: + activation: + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + comment_id: "" + comment_repo: "" + lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} + model: ${{ steps.generate_aw_info.outputs.model }} + secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Generate agentic run info + id: generate_aw_info + env: + GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} + GH_AW_INFO_VERSION: "latest" + GH_AW_INFO_AGENT_VERSION: "latest" + GH_AW_INFO_CLI_VERSION: "v0.64.4" + GH_AW_INFO_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + GH_AW_INFO_EXPERIMENTAL: "false" + GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" + GH_AW_INFO_STAGED: "false" + GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' + GH_AW_INFO_FIREWALL_ENABLED: "true" + GH_AW_INFO_AWF_VERSION: "v0.25.4" + GH_AW_INFO_AWMG_VERSION: "" + GH_AW_INFO_FIREWALL_TYPE: "squid" + GH_AW_COMPILED_STRICT: "true" + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); + await main(core, context); + - name: Validate COPILOT_GITHUB_TOKEN secret + id: validate-secret + run: ${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + - name: Checkout .github and .agents folders + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + sparse-checkout: | + .github + .agents + sparse-checkout-cone-mode: true + fetch-depth: 1 + - name: Check workflow file timestamps + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_WORKFLOW_FILE: "aw-auto-update.lock.yml" + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + await main(); + - name: Create prompt with built-in context + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + # poutine:ignore untrusted_checkout_exec + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh + { + cat << 'GH_AW_PROMPT_129f48edee93c656_EOF' + + GH_AW_PROMPT_129f48edee93c656_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_129f48edee93c656_EOF' + + Tools: create_pull_request, push_to_pull_request_branch, missing_tool, missing_data, noop + GH_AW_PROMPT_129f48edee93c656_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" + cat << 'GH_AW_PROMPT_129f48edee93c656_EOF' + + + The following GitHub context information is available for this workflow: + {{#if __GH_AW_GITHUB_ACTOR__ }} + - **actor**: __GH_AW_GITHUB_ACTOR__ + {{/if}} + {{#if __GH_AW_GITHUB_REPOSITORY__ }} + - **repository**: __GH_AW_GITHUB_REPOSITORY__ + {{/if}} + {{#if __GH_AW_GITHUB_WORKSPACE__ }} + - **workspace**: __GH_AW_GITHUB_WORKSPACE__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} + - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} + - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} + - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} + - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{/if}} + {{#if __GH_AW_GITHUB_RUN_ID__ }} + - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ + {{/if}} + - **checkouts**: The following repositories have been checked out and are available in the workspace: + - `$GITHUB_WORKSPACE` → `__GH_AW_GITHUB_REPOSITORY__` (cwd) [shallow clone, fetch-depth=1 (default)] + - **Note**: If a branch you need is not in the list above and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it without proper authentication. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: ["refs/pulls/open/*"]` for all open PR refs, or `fetch: ["main", "feature/my-branch"]` for specific branches). + + + GH_AW_PROMPT_129f48edee93c656_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" + cat << 'GH_AW_PROMPT_129f48edee93c656_EOF' + + GH_AW_PROMPT_129f48edee93c656_EOF + cat << 'GH_AW_PROMPT_129f48edee93c656_EOF' + {{#runtime-import .github/workflows/aw-auto-update.md}} + GH_AW_PROMPT_129f48edee93c656_EOF + } > "$GH_AW_PROMPT" + - name: Interpolate variables and render templates + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); + await main(); + - name: Substitute placeholders + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + + const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); + + // Call the substitution function + return await substitutePlaceholders({ + file: process.env.GH_AW_PROMPT, + substitutions: { + GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, + GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, + GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, + GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE + } + }); + - name: Validate prompt placeholders + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + # poutine:ignore untrusted_checkout_exec + run: bash ${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh + - name: Print prompt + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + # poutine:ignore untrusted_checkout_exec + run: bash ${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh + - name: Upload activation artifact + if: success() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: activation + path: | + /tmp/gh-aw/aw_info.json + /tmp/gh-aw/aw-prompts/prompt.txt + retention-days: 1 + + agent: + needs: activation + runs-on: ubuntu-latest + permissions: read-all + concurrency: + group: "gh-aw-copilot-${{ github.workflow }}" + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GH_AW_ASSETS_ALLOWED_EXTS: "" + GH_AW_ASSETS_BRANCH: "" + GH_AW_ASSETS_MAX_SIZE_KB: 0 + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_WORKFLOW_ID_SANITIZED: awautoupdate + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} + model: ${{ needs.activation.outputs.model }} + output: ${{ steps.collect_output.outputs.output }} + output_types: ${{ steps.collect_output.outputs.output_types }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Set runtime paths + id: set-runtime-paths + run: | + echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" >> "$GITHUB_OUTPUT" + echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" >> "$GITHUB_OUTPUT" + echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" >> "$GITHUB_OUTPUT" + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + ref: main + - name: Create gh-aw temp directory + run: bash ${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh + - name: Configure gh CLI for GitHub Enterprise + run: bash ${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh + env: + GH_TOKEN: ${{ github.token }} + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Checkout PR branch + id: checkout-pr + if: | + github.event.pull_request || github.event.issue.pull_request + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); + await main(); + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.4 + - name: Parse integrity filter lists + id: parse-guard-vars + env: + GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }} + GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} + run: bash ${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.4 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.4 ghcr.io/github/gh-aw-firewall/squid:0.25.4 ghcr.io/github/gh-aw-mcpg:v0.2.9 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + - name: Write Safe Outputs Config + run: | + mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_52bfaaa26afe65fd_EOF' + {"create_pull_request":{"draft":false,"labels":["automation"],"max":1,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_path_prefixes":[".github/",".agents/"],"title_prefix":"[Auto Update] "},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"if_no_changes":"warn","labels":["automation"],"max":1,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_path_prefixes":[".github/",".agents/"],"target":"*","title_prefix":"[Auto Update] "}} + GH_AW_SAFE_OUTPUTS_CONFIG_52bfaaa26afe65fd_EOF + - name: Write Safe Outputs Tools + run: | + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_77928e152c9bfecb_EOF' + { + "description_suffixes": { + "create_pull_request": " CONSTRAINTS: Maximum 1 pull request(s) can be created. Title will be prefixed with \"[Auto Update] \". Labels [\"automation\"] will be automatically added.", + "push_to_pull_request_branch": " CONSTRAINTS: Maximum 1 push(es) can be made. The target pull request title must start with \"[Auto Update] \"." + }, + "repo_params": {}, + "dynamic_tools": [] + } + GH_AW_SAFE_OUTPUTS_TOOLS_META_77928e152c9bfecb_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_2d02a88b923d571f_EOF' + { + "create_pull_request": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "draft": { + "type": "boolean" + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "repo": { + "type": "string", + "maxLength": 256 + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "missing_data": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "context": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "data_type": { + "type": "string", + "sanitize": true, + "maxLength": 128 + }, + "reason": { + "type": "string", + "sanitize": true, + "maxLength": 256 + } + } + }, + "missing_tool": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 512 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "tool": { + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "noop": { + "defaultMax": 1, + "fields": { + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + } + } + }, + "push_to_pull_request_branch": { + "defaultMax": 1, + "fields": { + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "pull_request_number": { + "issueOrPRNumber": true + } + } + } + } + GH_AW_SAFE_OUTPUTS_VALIDATION_2d02a88b923d571f_EOF + node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs + - name: Generate Safe Outputs MCP Server Config + id: safe-outputs-config + run: | + # Generate a secure random API key (360 bits of entropy, 40+ chars) + # Mask immediately to prevent timing vulnerabilities + API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${API_KEY}" + + PORT=3001 + + # Set outputs for next steps + { + echo "safe_outputs_api_key=${API_KEY}" + echo "safe_outputs_port=${PORT}" + } >> "$GITHUB_OUTPUT" + + echo "Safe Outputs MCP server will run on port ${PORT}" + + - name: Start Safe Outputs MCP HTTP Server + id: safe-outputs-start + env: + DEBUG: '*' + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + run: | + # Environment variables are set above to prevent template injection + export DEBUG + export GH_AW_SAFE_OUTPUTS_PORT + export GH_AW_SAFE_OUTPUTS_API_KEY + export GH_AW_SAFE_OUTPUTS_TOOLS_PATH + export GH_AW_SAFE_OUTPUTS_CONFIG_PATH + export GH_AW_MCP_LOG_DIR + + bash ${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh + + - name: Start MCP Gateway + id: start-mcp-gateway + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + set -eo pipefail + mkdir -p /tmp/gh-aw/mcp-config + + # Export gateway environment variables for MCP config and gateway script + export MCP_GATEWAY_PORT="80" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_API_KEY}" + export MCP_GATEWAY_API_KEY + export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" + mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" + export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export DEBUG="*" + + export GH_AW_ENGINE="copilot" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.9' + + mkdir -p /home/runner/.copilot + cat << GH_AW_MCP_CONFIG_4027a72012fb469c_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + { + "mcpServers": { + "github": { + "type": "stdio", + "container": "ghcr.io/github/github-mcp-server:v0.32.0", + "env": { + "GITHUB_HOST": "\${GITHUB_SERVER_URL}", + "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_READ_ONLY": "1", + "GITHUB_TOOLSETS": "pull_requests" + }, + "guard-policies": { + "allow-only": { + "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }}, + "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }}, + "min-integrity": "none", + "repos": "all" + } + } + }, + "safeoutputs": { + "type": "http", + "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", + "headers": { + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + }, + "guard-policies": { + "write-sink": { + "accept": [ + "*" + ] + } + } + } + }, + "gateway": { + "port": $MCP_GATEWAY_PORT, + "domain": "${MCP_GATEWAY_DOMAIN}", + "apiKey": "${MCP_GATEWAY_API_KEY}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + } + } + GH_AW_MCP_CONFIG_4027a72012fb469c_EOF + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw + - name: Clean git credentials + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh + - name: Execute GitHub Copilot CLI + id: agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 15 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.4 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json + GH_AW_PHASE: agent + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_VERSION: v0.64.4 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/detect_inference_access_error.sh + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Copy Copilot session state files to logs + if: always() + continue-on-error: true + run: | + # Copy Copilot session state files to logs folder for artifact collection + # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them + SESSION_STATE_DIR="$HOME/.copilot/session-state" + LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" + + if [ -d "$SESSION_STATE_DIR" ]; then + echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" + mkdir -p "$LOGS_DIR" + cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true + echo "Session state files copied successfully" + else + echo "No session-state directory found at $SESSION_STATE_DIR" + fi + - name: Stop MCP Gateway + if: always() + continue-on-error: true + env: + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" + - name: Redact secrets in logs + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); + await main(); + env: + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Append agent step summary + if: always() + run: bash ${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh + - name: Copy Safe Outputs + if: always() + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + run: | + mkdir -p /tmp/gh-aw + cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true + - name: Ingest agent output + id: collect_output + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); + await main(); + - name: Parse agent logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + await main(); + - name: Parse MCP Gateway logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); + await main(); + - name: Print firewall logs + if: always() + continue-on-error: true + env: + AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs + run: | + # Fix permissions on firewall logs so they can be uploaded as artifacts + # AWF runs with sudo, creating files owned by root + sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true + # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) + if command -v awf &> /dev/null; then + awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" + else + echo 'AWF binary not installed, skipping firewall log summary' + fi + - name: Write agent output placeholder if missing + if: always() + run: | + if [ ! -f /tmp/gh-aw/agent_output.json ]; then + echo '{"items":[]}' > /tmp/gh-aw/agent_output.json + fi + - name: Upload agent artifacts + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: agent + path: | + /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/sandbox/agent/logs/ + /tmp/gh-aw/redacted-urls.log + /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/agent/ + /tmp/gh-aw/safeoutputs.jsonl + /tmp/gh-aw/agent_output.json + /tmp/gh-aw/aw-*.patch + /tmp/gh-aw/aw-*.bundle + if-no-files-found: ignore + - name: Upload firewall audit logs + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: firewall-audit-logs + path: | + /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/sandbox/firewall/audit/ + if-no-files-found: ignore + + conclusion: + needs: + - activation + - agent + - detection + - safe_outputs + if: always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true') + runs-on: ubuntu-slim + permissions: + contents: write + issues: write + pull-requests: write + concurrency: + group: "gh-aw-conclusion-aw-auto-update" + cancel-in-progress: false + outputs: + noop_message: ${{ steps.noop.outputs.noop_message }} + tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} + total_count: ${{ steps.missing_tool.outputs.total_count }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Process No-Op Messages + id: noop + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_NOOP_MAX: "1" + GH_AW_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/noop.cjs'); + await main(); + - name: Record Missing Tool + id: missing_tool + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" + GH_AW_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + await main(); + - name: Handle Agent Failure + id: handle_agent_failure + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_WORKFLOW_ID: "aw-auto-update" + GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} + GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} + GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} + GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_GROUP_REPORTS: "false" + GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_TIMEOUT_MINUTES: "15" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + await main(); + - name: Handle No-Op Message + id: handle_noop_message + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} + GH_AW_NOOP_REPORT_AS_ISSUE: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + await main(); + - name: Handle Create Pull Request Error + id: handle_create_pr_error + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_create_pr_error.cjs'); + await main(); + + detection: + needs: agent + if: > + always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true') + runs-on: ubuntu-latest + outputs: + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + # --- Threat Detection --- + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.4 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.4 ghcr.io/github/gh-aw-firewall/squid:0.25.4 + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + for f in /tmp/gh-aw/aw-*.bundle; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Agentic Workflow Auto-Update" + WORKFLOW_DESCRIPTION: "Keeps agentic workflows up to date by running `gh aw upgrade` and `gh aw compile` daily.\nIf changes are detected, pushes them to a long-lived branch and creates or updates a PR." + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); + await main(); + - name: Ensure threat-detection directory and log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.4 + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 20 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.4 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + GH_AW_PHASE: detection + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_VERSION: v0.64.4 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Upload threat detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: detection + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Parse and conclude threat detection + id: detection_conclusion + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + + safe_outputs: + needs: + - activation + - agent + - detection + if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success' + runs-on: ubuntu-slim + permissions: + contents: write + issues: write + pull-requests: write + timeout-minutes: 15 + env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/aw-auto-update" + GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} + GH_AW_WORKFLOW_ID: "aw-auto-update" + GH_AW_WORKFLOW_NAME: "Agentic Workflow Auto-Update" + outputs: + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} + create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} + created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }} + created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }} + process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }} + push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@7cae8cd356c7905aeda72eb08e1d0b4501310c23 # v0.64.4 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Checkout repository + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }} + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + persist-credentials: false + fetch-depth: 1 + - name: Configure Git credentials + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Configure GH_HOST for enterprise compatibility + id: ghes-host-config + shell: bash + run: | + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" + - name: Process Safe Outputs + id: process_safe_outputs + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"draft\":false,\"labels\":[\"automation\"],\"max\":1,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"title_prefix\":\"[Auto Update] \"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"labels\":[\"automation\"],\"max\":1,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"target\":\"*\",\"title_prefix\":\"[Auto Update] \"}}" + GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); + await main(); + - name: Upload Safe Output Items + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: safe-output-items + path: /tmp/gh-aw/safe-output-items.jsonl + if-no-files-found: ignore + diff --git a/.github/workflows/aw-auto-update.md b/.github/workflows/aw-auto-update.md new file mode 100644 index 00000000000..2fcf6524cd1 --- /dev/null +++ b/.github/workflows/aw-auto-update.md @@ -0,0 +1,61 @@ +--- +description: | + Keeps agentic workflows up to date by running `gh aw upgrade` and `gh aw compile` daily. + If changes are detected, pushes them to a long-lived branch and creates or updates a PR. + +on: + schedule: every 24h + workflow_dispatch: + +timeout-minutes: 15 + +permissions: read-all + +network: + allowed: + - defaults + +checkout: + ref: main + +tools: + github: + toolsets: [pull_requests] + min-integrity: none + bash: true + +safe-outputs: + create-pull-request: + draft: false + title-prefix: "[Auto Update] " + labels: [automation] + max: 1 + push-to-pull-request-branch: + target: "*" + title-prefix: "[Auto Update] " + labels: [automation] + max: 1 +--- + +# Agentic Workflow Auto-Update + +You are a maintenance bot that keeps the repository's agentic workflow infrastructure current. + +## Task + +1. **Upgrade**: Run `gh aw upgrade` to update the gh-aw CLI version and apply any codemods. +2. **Compile**: Run `gh aw compile` to recompile all workflows and verify 0 errors. +3. **Check for changes**: Run `git diff` to see if anything changed. +4. **If no changes**: Report "Already up to date" and exit. +5. **If changes exist**: + - Check if an open PR titled `[Auto Update] Agentic workflows` already exists (search open PRs). + - If a PR exists, push the changes to its branch (`agentics/auto-update-gh-aw`) to update it. Leave a brief comment noting what changed (e.g. "Updated gh-aw-actions/setup from vX to vY"). + - If no PR exists, create a new PR from branch `agentics/auto-update-gh-aw` to `main` with title `[Auto Update] Agentic workflows` and a body summarizing the changes. + +## Rules + +- Only commit changes to files managed by `gh aw`: `.github/workflows/`, `.github/aw/`, `.github/agents/`. +- Use a single commit with message: `Update agentic workflows via gh aw upgrade`. +- The branch name must always be `agentics/auto-update-gh-aw`. +- If `gh aw compile` reports errors, do **not** create or update a PR. Instead, report the errors and exit. +- Be concise in PR descriptions and comments. From 3009471478dc08a3e1e47cb6e7ce002802a81ee2 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 31 Mar 2026 14:47:34 +0200 Subject: [PATCH 17/19] Add regression test for #6715: land is a valid identifier (#19478) Verifies that land, lor, lxor, lsl, lsr, and asr can be used as valid identifiers after the ML compatibility removal in PR #19143. Fixes #6715 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../ErrorMessages/DiagnosticRegressionTests.fs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs index c8517a57e69..99d39b28fcd 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/DiagnosticRegressionTests.fs @@ -3,6 +3,23 @@ module ErrorMessages.DiagnosticRegressionTests open Xunit open FSharp.Test.Compiler +// https://github.com/dotnet/fsharp/issues/6715 +[] +let ``Issue 6715 - land is a valid identifier after ML compat removal`` () = + FSharp + """ +let land = 3 +let lor = 4 +let lxor = 5 +let lsl = 6 +let lsr = 7 +let asr = 8 +let sum = land + lor + lxor + lsl + lsr + asr + """ + |> asLibrary + |> typecheck + |> shouldSucceed + // https://github.com/dotnet/fsharp/issues/15655 [] let ``Issue 15655 - error codes 999 and 3217 are distinct`` () = From 4c0098280aae0786543cdc487d2ed90e7128b122 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:10:16 +0000 Subject: [PATCH 18/19] Add warning FS3885 for let-in with multi-line body in sequence expressions Agent-Logs-Url: https://github.com/dotnet/fsharp/sessions/740bb677-5347-48ad-9001-278dfc1631e3 Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 1 + .../Checking/Expressions/CheckExpressions.fs | 10 +++ src/Compiler/FSComp.txt | 2 + src/Compiler/Facilities/LanguageFeatures.fs | 3 + src/Compiler/Facilities/LanguageFeatures.fsi | 1 + .../ErrorMessages/WarnExpressionTests.fs | 86 +++++++++++++++++++ 6 files changed, 103 insertions(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index d5c2087765e..1388a605522 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -22,3 +22,4 @@ * Added warning FS3884 when a function or delegate value is used as an interpolated string argument. ([PR #19289](https://github.com/dotnet/fsharp/pull/19289)) * Add `#version;;` directive to F# Interactive to display version and environment information. ([Issue #13307](https://github.com/dotnet/fsharp/issues/13307), [PR #19332](https://github.com/dotnet/fsharp/pull/19332)) +* Added warning FS3885 when `let ... in` with explicit `in` keyword is used in a sequence expression and the body extends to subsequent lines, causing unexpected scoping. ([Issue #7091](https://github.com/dotnet/fsharp/issues/7091), [PR #19526](https://github.com/dotnet/fsharp/pull/19526)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 635a0dff045..91de1d8c442 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -6041,6 +6041,16 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE errorR(Error(FSComp.SR.tcConstructRequiresComputationExpression(), leadingKeyword.Range)) | _ -> () + // Warn when 'let ... in' has an explicit 'in' keyword and the body is a sequential expression + // spanning multiple lines. This indicates the user likely intended the 'let ... in' to scope only + // over the expression on the same line, but the parser greedily consumed subsequent lines as body. + match letOrUse with + | { Trivia = { InKeyword = Some inRange }; Body = SynExpr.Sequential(expr2 = expr2) } + when g.langVersion.SupportsFeature LanguageFeature.WarnOnLetInSequenceExpression + && expr2.Range.StartLine > inRange.StartLine -> + warning(Error(FSComp.SR.tcLetExpressionWithInHasMultiLineBody(), inRange)) + | _ -> () + TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr id | SynExpr.TryWith (synBodyExpr, synWithClauses, mTryToLast, spTry, spWith, trivia) -> diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index a4007147b9a..8835f841443 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1809,8 +1809,10 @@ featureWarnWhenFunctionValueUsedAsInterpolatedStringArg,"Warn when a function va featureMethodOverloadsCache,"Support for caching method overload resolution results for improved compilation performance." featureImplicitDIMCoverage,"Implicit dispatch slot coverage for default interface member implementations" featurePreprocessorElif,"#elif preprocessor directive" +featureWarnOnLetInSequenceExpression,"Warn when 'let ... in' is used in a sequence expression and the body extends to subsequent lines" 3880,optsLangVersionOutOfSupport,"Language version '%s' is out of support. The last .NET SDK supporting it is available at https://dotnet.microsoft.com/en-us/download/dotnet/%s" 3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." 3882,lexHashElifMustBeFirst,"#elif directive must appear as the first non-whitespace character on a line" 3883,lexHashElifMustHaveIdent,"#elif directive should be immediately followed by an identifier" 3884,tcFunctionValueUsedAsInterpolatedStringArg,"This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments." +3885,tcLetExpressionWithInHasMultiLineBody,"The use of 'in' in 'let ... in' on a single line followed by additional code on subsequent lines causes all subsequent lines to be part of the 'let' body. This may lead to unexpected scoping. Either remove the 'in' keyword and rely on indentation, or add parentheses to clarify the intended scope." diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 1bc31837052..0cc80ce4541 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -108,6 +108,7 @@ type LanguageFeature = | MethodOverloadsCache | ImplicitDIMCoverage | PreprocessorElif + | WarnOnLetInSequenceExpression /// LanguageVersion management type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) = @@ -251,6 +252,7 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) // Put stabilized features here for F# 11.0 previews via .NET SDK preview channels LanguageFeature.WarnWhenFunctionValueUsedAsInterpolatedStringArg, languageVersion110 LanguageFeature.PreprocessorElif, languageVersion110 + LanguageFeature.WarnOnLetInSequenceExpression, languageVersion110 // Difference between languageVersion110 and preview - 11.0 gets turned on automatically by picking a preview .NET 11 SDK // previewVersion is only when "preview" is specified explicitly in project files and users also need a preview SDK @@ -453,6 +455,7 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) | LanguageFeature.MethodOverloadsCache -> FSComp.SR.featureMethodOverloadsCache () | LanguageFeature.ImplicitDIMCoverage -> FSComp.SR.featureImplicitDIMCoverage () | LanguageFeature.PreprocessorElif -> FSComp.SR.featurePreprocessorElif () + | LanguageFeature.WarnOnLetInSequenceExpression -> FSComp.SR.featureWarnOnLetInSequenceExpression () /// Get a version string associated with the given feature. static member GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index fd6182c9d3e..1a247cda15e 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -99,6 +99,7 @@ type LanguageFeature = | MethodOverloadsCache | ImplicitDIMCoverage | PreprocessorElif + | WarnOnLetInSequenceExpression /// LanguageVersion management type LanguageVersion = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs index 942ab64dfcd..e07334ebdec 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/WarnExpressionTests.fs @@ -220,3 +220,89 @@ let main _argv = """ |> typecheck |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/7091 + [] + let ``Warn when let-in has multi-line sequential body in do block``() = + FSharp """ +module Test +let x = 42 +do + let x = 1 in x + 1 + x + """ + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 3885, Line 5, Col 15, Line 5, Col 17, + "The use of 'in' in 'let ... in' on a single line followed by additional code on subsequent lines causes all subsequent lines to be part of the 'let' body. This may lead to unexpected scoping. Either remove the 'in' keyword and rely on indentation, or add parentheses to clarify the intended scope.") + (Warning 20, Line 5, Col 18, Line 5, Col 23, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + (Warning 20, Line 5, Col 5, Line 6, Col 6, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + ] + + // https://github.com/dotnet/fsharp/issues/7091 + [] + let ``No warning for single-line let-in``() = + FSharp """ +module Test +let result = let x = 1 in x + 1 + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/7091 + [] + let ``No warning for let without in keyword``() = + FSharp """ +module Test +let x = 42 +do + let x = 1 + printfn "%d" x + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/7091 + [] + let ``No warning for let-in without langversion preview``() = + FSharp """ +module Test +let x = 42 +do + let x = 1 in x + 1 + x + """ + |> withLangVersion "9.0" + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 20, Line 5, Col 18, Line 5, Col 23, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + (Warning 20, Line 5, Col 5, Line 6, Col 6, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + ] + + // https://github.com/dotnet/fsharp/issues/7091 + [] + let ``Warn when let-in extends scope in function body``() = + FSharp """ +module Test +let f () = + let x = 1 in x + 1 + printfn "hello" + """ + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 3885, Line 4, Col 15, Line 4, Col 17, + "The use of 'in' in 'let ... in' on a single line followed by additional code on subsequent lines causes all subsequent lines to be part of the 'let' body. This may lead to unexpected scoping. Either remove the 'in' keyword and rely on indentation, or add parentheses to clarify the intended scope.") + (Warning 20, Line 4, Col 18, Line 4, Col 23, + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") + ] From 6259b63e0a39ffd6b1b61961c66a436861adcdb1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:18:33 +0000 Subject: [PATCH 19/19] Update release notes wording for FS3885 Agent-Logs-Url: https://github.com/dotnet/fsharp/sessions/740bb677-5347-48ad-9001-278dfc1631e3 Co-authored-by: abonie <20281641+abonie@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 1388a605522..4161d0e6c95 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -22,4 +22,4 @@ * Added warning FS3884 when a function or delegate value is used as an interpolated string argument. ([PR #19289](https://github.com/dotnet/fsharp/pull/19289)) * Add `#version;;` directive to F# Interactive to display version and environment information. ([Issue #13307](https://github.com/dotnet/fsharp/issues/13307), [PR #19332](https://github.com/dotnet/fsharp/pull/19332)) -* Added warning FS3885 when `let ... in` with explicit `in` keyword is used in a sequence expression and the body extends to subsequent lines, causing unexpected scoping. ([Issue #7091](https://github.com/dotnet/fsharp/issues/7091), [PR #19526](https://github.com/dotnet/fsharp/pull/19526)) +* Added warning FS3885 when `let ... in` with explicit `in` keyword has a body that extends to subsequent lines, which causes all subsequent lines to become part of the `let` body due to the parser's greedy behavior. ([Issue #7091](https://github.com/dotnet/fsharp/issues/7091), [PR #19526](https://github.com/dotnet/fsharp/pull/19526))