opencomponents/oc

Rollback component

jankowiakmaria opened this issue ยท 6 comments

Issue description

Recently we've had an issue when the component had to be quickly rollback to the previous version.
The procedure required going back in the git history and then manually publishing the component.
It was an error prone and not so quick solution.

Expected behaviour

It would be nice to have some kind of rollback mechanism in place which would republish specified version of component (with the latest version of it)

The command could look like:

oc rollback <componentPath> <rollbackVersion> [newVersion]

where
rollbackVersion is the existing version of component (the one we want to republish)
newVersion is the republished version of component (defaulting to the latest one with increased patch - when semver is supported)

Questions/possible issues

  • How to implement?

    download the specified version of component and then publish with new version (Q: Does the package.json file in the component package need to be updated as well?)

  • How can we distinguish between "normal" and "republished" (rolled back) version of component?

    We could add build metadata that would add something like +rb.1.3.4 to the version of component during the rollback (https://semver.org/#spec-item-10)

  • What if semver is not supported?

    We can require semver to be supported or newVersion to be specified

Other Comments

I'd like to gather some opinions/comments before [possibly] starting implementing this feature.

  • I believe the package.json of the component will need to be updated.
  • I like the idea of adding metadata to link back to the original version
  • metadata does not factor into precedence, but interestingly, any version with a pre-release flag attached will have a lower precedence than its non-prerelease counterpart. Depending on how we apply rollbacks,, we should consider making rollbacks a pre-release so that developers don't have to double bump the version. The pre release version affects the precedence, although exactly how is unclear to me at the moment.

Eg: possibly this type of scenario could exist.
0.9.1 -> 1.0.0 -> 1.0.1 -> 1.0.2-rollback.1+v1.0.0 -> 1.0.2-rollback.2+v0.9.1 -> 1.0.2

With this, rollbacks could also be done without forcing any git changes if this is desired.

seif commented

This feels kinda strange to me. Could outcome be achieved by unpublishing a version? Where unpublishing a version would make the registry ignore it so previous 'good' version would be surfaced.

I think the suggested approach would be really hairy when the number of rollbacks goes high! Instead, a similar approach to npm unpublish would be more desirable. As @seif mentioned, OC-Registry could respect to deprecated version and serve previous good version.

Alternatively, version management for prod traffic for serving OC components could be completely independent of OC-Registry itself. The sequence would be:

  • A Request comes to website with coponent foo included
  • website talks to OC version management service (A service that keeps a list of prod ready component name and version. For example foo:0.1.1)
  • Website will render webpage with foo component html

This way developers can keep publishing components to OC-registry without the fear of breaking the prod and once they are confident with a version on prod, they can update OC version management service to store the stable version. In this case the revert process would be just updating the OC version management service with the last good known version.

I still think that it should be the consumer's responsibility to decide whether or not to reference the latest or a specific version of a component. And additionally to have in place a system that can easily pin/unpin a specific component/version w/o the need of a full website deploy for instance. If we really need to have a feature at the OpenComponents platform level I'd vote for something more soft like @seif suggested, but my personal preference would still be having in place what I've just described above. and basically what's @NimaSoroush is proposing is a way of achieving that.

I honestly like the simplicity of this proposed approach. The issue is when you have a version that needs to be rolled-back for a security problem: in that scenario, the bad version is still there.

The other proposed solution (the kind of unpublish approach, also discussed in #524 but never been implemented) would be my preferred approach. The idea is that during the unpublish you wouldn't really unpublish but you would mark the component as locked and the registry would return a specific error when consuming the component with strict versioning, or behave as it wasn't ever published when weak versioning is used.
Example: oc lock component 1.2.3 => curl https://registry/component/1.2.X => 1.2.2, curl https://registry/component/1.2.3 => 401 error

๐Ÿ‘ or ๐Ÿ‘Ž ? In case, we can consolidate the two github threads

A perfect solution could be a combination of both approaches. Locking a vulnerable version is definitely a valid edge case, although implementing the feature would be complicated in case the number of fallbacks goes high! for example, if you want to lock hundreds of versions which are eventually falling back on each other.

for (i=1 to i=<the big number>) {
  oc lock component 1.2.i
}

This case if curl https://registry/component/1.2.<the big number> requested oc registry needs to process all versions to fallback to 1.2.0. in these kind of situations probably a delete version would be better than lock