Skip to content

WatchConfig.UpsertEntry silently deletes existing contexts when re-upserting a watched file #610

Open

Description

@aryarathoree

Describe the bug

When a file is being watched across multiple contexts (e.g. ["dev", "staging"]), re-running microcks import --watch <file> on an existing context—or calling WatchConfig.UpsertEntry with a context already present—silently deletes all other contexts associated with that file from .config/microcks/watch.

In pkg/config/localconfig.go:

func (w *WatchConfig) UpsertEntry(entry WatchEntry) {
    for i, e := range w.Entries {
        if e.FilePath == entry.FilePath {
            contexts := w.Entries[i].Context
            if !slices.Contains(contexts, entry.Context[0]) {
                entry.Context = append(entry.Context, contexts...)
            }
            w.Entries[i] = entry
            return
        }
    }
    w.Entries = append(w.Entries, entry)
}

If entry.Context[0] is already in contexts, the if !slices.Contains(...) check evaluates to false and does nothing. Because entry.Context only contains the single context from the current invocation, w.Entries[i] = entry replaces the existing context slice with only entry.Context, wiping out all other contexts.

Additionally:

  • If entry.Context is empty, accessing entry.Context[0] unconditionally panics with runtime error: index out of range [0] with length 0.
  • If entry.Context contains multiple items, only index 0 is ever evaluated.

Expected behavior

WatchConfig.UpsertEntry should preserve all existing contexts for a file while adding any new context without duplicates. Re-importing or updating a watched file from one context must not delete other contexts that are monitoring the same file.

Actual behavior

When re-upserting a file with an already existing context, all other contexts previously attached to the entry are discarded, leaving only the single re-upserted context in the watch configuration.

How to Reproduce?

Reproducer

package main

import (
    "fmt"
    "github.com/microcks/microcks-cli/pkg/config"
)

func main() {
    cfg := config.WatchConfig{
        Entries: []config.WatchEntry{
            {FilePath: "api.yaml", Context: []string{"dev"}},
        },
    }

    // 1. Add "staging" -> Entry has ["staging", "dev"]
    cfg.UpsertEntry(config.WatchEntry{FilePath: "api.yaml", Context: []string{"staging"}})
    fmt.Printf("After adding staging: %v\n", cfg.Entries[0].Context)

    // 2. Re-import / re-upsert from "staging"
    cfg.UpsertEntry(config.WatchEntry{FilePath: "api.yaml", Context: []string{"staging"}, MainArtifact: true})
    fmt.Printf("After re-upserting staging: %v\n", cfg.Entries[0].Context)

    // Output: [staging] --> "dev" context was deleted!
}

Steps to Reproduce via CLI

  1. Register a file in watch mode across two contexts (dev and staging).
  2. Run microcks import --watch <file> again while on the staging context.
  3. Check the watch configuration file: <file> now only lists staging, and dev has been deleted.

Microcks version or git rev

master

Install method (docker-compose, helm chart, operator, docker-desktop extension,...)

No response

Additional information

I would be happy to submit a PR with unit test coverage if the team agrees!

Activity

  1. aryarathoree commented on Nov 4, 2026

    @aryarathoree
    ContributorAuthor

    Hey @Caesarsage , I would like to discuss this issue before proceeding with the implementation.

  2. Caesarsage commented on Nov 4, 2026

    @Caesarsage
    Collaborator

    Thanks @aryarathoree, confirmed. Merging the contexts without duplicates and returning an error on an empty list sounds right. #614 already guards the empty case, so please coordinate with @aniket866 so we end up with one PR.

  3. aryarathoree commented on Nov 4, 2026

    @aryarathoree
    ContributorAuthor

    @Caesarsage sure, will co-ordinate with him.

  4. Caesarsage commented on Nov 4, 2026

    @Caesarsage
    Collaborator

    @aryarathoree thanks for the follow-up. Let's keep it simple: please open your own PR with Fixes #610, covering both the context merge and the empty-context check (reject blank names too). If you reuse code from #614, a Co-authored-by line for @aniket866 would be nice.

  5. aryarathoree commented on Nov 4, 2026

    @aryarathoree
    ContributorAuthor

    @Caesarsage okay, working on this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions