Skip to content

stacker sync does not persist config_contract to project_app table #257

Description

@vsilent

Bug Description

stacker sync does not persist the config_contract section from stacker.yml to the project_app.config_contract database column. The field remains NULL for all project apps after sync.

Steps to Reproduce

  1. Create a stacker.yml with a populated config_contract section:

    config_contract:
      services:
        app:
          fields:
            SECRET_KEY:
              mutability: generated
              type: alphanumeric
              length: 32
              display: password
  2. Run stacker sync

  3. Query the database:

    SELECT app_code, config_contract FROM project_app WHERE project_id = <id>;
  4. Observe that config_contract IS NULL for all rows

Expected Behavior

Per the STACKER_SYNC_PLAN.md, config_contract should be persisted:

Project app configuration is stored in:

  • project_app.environment
  • project_app.ports
  • project_app.volumes
  • project_app.config_files
  • project_app.config_contract ← Should be written

The regression tests also specify:

"config contracts not being lost during sync"

Actual Behavior

config_contract is NULL in the project_app table after stacker sync.

Root Cause

In src/project_app/sync.rs, the build_project_app() function constructs a ProjectApp but never sets the config_contract field:

fn build_project_app(...) -> models::ProjectApp {
    let mut project_app = models::ProjectApp::new(...);
    
    project_app.environment = ...;
    project_app.ports = ...;
    project_app.volumes = ...;
    project_app.domain = ...;
    project_app.restart_policy = ...;
    project_app.command = ...;
    project_app.entrypoint = ...;
    project_app.networks = ...;
    // config_contract is NEVER SET ← BUG
    project_app
}

Workaround

stacker submit (marketplace submission) DOES persist config_contract as part of the template payload. The relevant code in src/console/commands/cli/submit.rs:

let config_contract = serde_json::to_value(&config.config_contract)?;
if config_contract
    .get("services")
    .and_then(|services| services.as_object())
    .is_some_and(|services| !services.is_empty())
{
    body["config_contract"] = config_contract;
}

Impact

  • Stack Builder UI cannot display config contract fields for synced projects
  • Developers must use stacker submit to persist config contracts
  • The sync plan's acceptance criteria is not met

Environment

  • Stacker CLI version: 0.3.3
  • Command: stacker sync --json

Additional Context

The STACKER_SYNC_PLAN.md explicitly lists config_contract as a field that should be synchronized:

Store in PostgreSQL
Store non-secret, declarative configuration:

  • app image;
  • app name and code;
  • non-secret environment values;
  • ports;
  • volumes;
  • domains;
  • restart policy;
  • config contract; ← Listed as required

The plan also includes this regression test:

"config contracts not being lost during sync"

Activity

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